Ryan-CW hace 3 años
padre
commit
2dd2d68fcb

+ 4 - 50
.gitignore

@@ -1,52 +1,6 @@
 # Prerequisites
-*.d
+# SConscript
 
-# Object files
-*.o
-*.ko
-*.obj
-*.elf
-
-# Linker output
-*.ilk
-*.map
-*.exp
-
-# Precompiled Headers
-*.gch
-*.pch
-
-# Libraries
-*.lib
-*.a
-*.la
-*.lo
-
-# Shared objects (inc. Windows DLLs)
-*.dll
-*.so
-*.so.*
-*.dylib
-
-# Executables
-*.exe
-*.out
-*.app
-*.i*86
-*.x86_64
-*.hex
-
-# Debug files
-*.dSYM/
-*.su
-*.idb
-*.pdb
-
-# Kernel Module Compile Results
-*.mod*
-*.cmd
-.tmp_versions/
-modules.order
-Module.symvers
-Mkfile.old
-dkms.conf
+# 平台移植层
+platform/linux/*
+platform/FreeRTOS/*

+ 33 - 0
SConscript

@@ -0,0 +1,33 @@
+import os
+from building import *
+
+# get current directory
+cwd = GetCurrentDir()
+
+# The set of source files associated with this SConscript file.
+src = Glob('common/*.c')
+src += Glob('ioLibrary/*.c')
+src += Glob('ioLibrary/wizchip/*.c')
+src += Glob('ioLibrary/DHCP/*.c')
+src += Glob('ioLibrary/DNS/*.c')
+src += Glob('ioLibrary/W5500/*.c')
+src += Glob('W5500Client/*.c')
+src += Glob('platform/RT-Thread/*.c')
+
+path = [cwd + '/common']
+path += [cwd + '/ioLibrary']
+path += [cwd + '/ioLibrary/wizchip']
+path += [cwd + '/ioLibrary/DHCP']
+path += [cwd + '/ioLibrary/DNS']
+path += [cwd + '/ioLibrary/W5500']
+path += [cwd + '/W5500Client']
+path += [cwd + '/platform/RT-Thread']
+
+if GetDepend(['PKG_USING_RYANW5500_EXAMPLE']):
+    src += Glob('example/*.c')
+    path += [cwd + '/example']
+
+group = DefineGroup('RyanW5500', src, depend=[
+                    "PKG_USING_RYANW5500"], CPPPATH=path)
+
+Return('group')

+ 293 - 0
W5500Client/RyanW5500.c

@@ -0,0 +1,293 @@
+#define DBG_ENABLE
+
+#define DBG_SECTION_NAME ("w5500")
+#define DBG_LEVEL LOG_LVL_INFO
+#define DBG_COLOR
+
+#include "RyanW5500Store.h"
+
+/**
+ * @brief W5500中断回调函数
+ *
+ * @param argument
+ */
+void RyanW5500IRQCallback(void *argument)
+{
+    rt_event_send(RyanW5500Entry.W5500EventHandle, RyanW5500IRQBit);
+}
+
+/**
+ * @brief 获取当前SPI总线资源
+ *
+ */
+void RyanW5500CriticalEnter(void)
+{
+    rt_mutex_take(RyanW5500Entry.W5500SpiMutexHandle, RT_WAITING_FOREVER);
+}
+
+/**
+ * @brief 释放当前SPI总线资源
+ *
+ */
+void RyanW5500CriticalExit(void)
+{
+    rt_mutex_release(RyanW5500Entry.W5500SpiMutexHandle);
+}
+
+void RyanW5500NetDevInfoUpdate(struct netdev *netdev)
+{
+    uint8_t linkState;
+    wiz_NetInfo netinfo = {0};
+    ctlnetwork(CN_GET_NETINFO, (void *)&netinfo);                                // 获取网络信息
+    netdev_low_level_set_ipaddr(netdev, (const ip_addr_t *)&netinfo.ip);         // 设置网络接口设备 IP 地址。
+    netdev_low_level_set_gw(netdev, (const ip_addr_t *)&netinfo.gw);             // 设置网络接口设备网关地址
+    netdev_low_level_set_netmask(netdev, (const ip_addr_t *)&netinfo.sn);        // 设置网络接口设备网络掩码地址。
+    netdev_low_level_set_dns_server(netdev, 0, (const ip_addr_t *)&netinfo.dns); // 设置网络接口设备DNS服务器地址
+    memcpy(netdev->hwaddr, (const void *)&netinfo.mac, netdev->hwaddr_len);      // 设置mac地址
+
+    netdev_low_level_set_dhcp_status(netdev, (gWIZNETINFO.dhcp == NETINFO_DHCP) ? RT_TRUE : RT_FALSE);
+
+    ctlwizchip(CW_GET_PHYLINK, &linkState);
+    netdev_low_level_set_link_status(netdev, PHY_LINK_ON == linkState ? RT_TRUE : RT_FALSE);
+}
+
+/**
+ * @brief 网络初始化
+ *
+ * @param netdev
+ * @return int
+ */
+int RyanW5500NetWorkInit(struct netdev *netdev)
+{
+
+    uint8_t MaintainFlag = 0; // dhcp续租标志
+
+    // nedev用户手动设置了ip / gw / mask / dnsService
+    if (RyanW5500Entry.netDevFlag & netDevSetDevInfo)
+    {
+
+        RyanW5500Entry.netDevFlag &= ~netDevSetDevInfo;
+        for (uint8_t socket = 0; socket < 8; socket++)
+            wiz_closesocket(socket);
+
+        gWIZNETINFO.dhcp = netdev_is_dhcp_enabled(netdev) ? NETINFO_DHCP : NETINFO_STATIC;
+        goto next;
+    }
+
+    // nedev用户使能了dhcp
+    if (RyanW5500Entry.netDevFlag & netDevDHCP)
+    {
+        RyanW5500Entry.netDevFlag &= ~netDevDHCP;
+        for (uint8_t socket = 0; socket < 8; socket++)
+            wiz_closesocket(socket);
+
+        gWIZNETINFO.dhcp = netdev_is_dhcp_enabled(netdev) ? NETINFO_DHCP : NETINFO_STATIC;
+        MaintainFlag = 0;
+        goto next;
+    }
+
+    // dhcp租期判断
+    if (NETINFO_DHCP == gWIZNETINFO.dhcp)
+    {
+        if (getDHCPRemainLeaseTime() < 10 * 1000) // 如果租期只剩余10秒,重新获取ip
+        {
+            LOG_I("dhcp租期接近超时, 重新获取ip");
+            MaintainFlag = 0;
+            goto next;
+        }
+
+        if (getDHCPRemainLeaseTime() < (getDHCPLeaseTime() / 2)) // 超过一半就开始续租
+        {
+            LOG_I("dhcp续租");
+            MaintainFlag = 1;
+            goto next;
+        }
+    }
+
+    uint8_t linkState = 0;
+    ctlwizchip(CW_GET_PHYLINK, &linkState);
+    if (PHY_LINK_ON == linkState && netdev_is_link_up(netdev)) // netdev状态和设备状态匹配,不进行下面操作
+        return 0;
+
+    if (PHY_LINK_ON == linkState) // w5500处于link状态,更新信息后就退出
+    {
+        LOG_D("link State: %d\r\n", linkState);
+        RyanW5500NetDevInfoUpdate(netdev);
+        return 0;
+    }
+
+next:
+    if (NETINFO_DHCP == gWIZNETINFO.dhcp)
+    {
+        if (0 == MaintainFlag)
+        {
+            memset(gWIZNETINFO.ip, 0, 4);
+            memset(gWIZNETINFO.sn, 0, 4);
+            memset(gWIZNETINFO.gw, 0, 4);
+            memset(gWIZNETINFO.dns, 0, 4);
+        }
+
+        uint32_t dhcpState = DHCP_run(MaintainFlag); // MaintainFlag续租
+        if (dhcpState != 0)
+        {
+            ctlnetwork(CN_SET_NETINFO, (void *)&gWIZNETINFO); // 从网络信息结构设置网络信息
+            RyanW5500NetDevInfoUpdate(netdev);
+            return -1;
+        }
+    }
+
+    ctlnetwork(CN_SET_NETINFO, (void *)&gWIZNETINFO); // 从网络信息结构设置网络信息
+    for (uint8_t count = 0; count < 100; count++)     // 测试link是否正常
+    {
+        ctlwizchip(CW_GET_PHYLINK, &linkState);
+        if (PHY_LINK_ON == linkState)
+            break;
+        delay(20);
+    }
+
+    RyanW5500NetDevInfoUpdate(netdev);
+
+    if (PHY_LINK_ON != linkState)
+        return -1;
+
+    setSIMR(0xff); // 启用所有socket通道中断
+    setIMR(0x0);   // 禁用所有通用中断,不使用
+    for (uint8_t i = 0; i < 8; i++)
+        setSn_IMR(i, RyanW5500SnIMR);
+
+    return 0;
+}
+
+static void wizIntDataTask(void *parameter)
+{
+    uint8_t ir = 0,
+            sir = 0,
+            sn_ir = 0;
+    struct netdev *netdev = (struct netdev *)parameter;
+
+    platformTimer_t netWorkTimer = {0};
+    platformTimerCutdown(&netWorkTimer, 0);
+
+    while (1)
+    {
+
+        // 500毫秒检查一次网络状态和监听套接字
+        if (0 == platformTimerRemain(&netWorkTimer))
+        {
+            if (-1 == RyanW5500NetWorkInit(netdev))
+            {
+                LOG_D("网络没有连接");
+                delay(500);
+                continue;
+            }
+
+            platformTimerCutdown(&netWorkTimer, 1000);
+        }
+
+        rt_event_recv(RyanW5500Entry.W5500EventHandle, RyanW5500IRQBit,
+                      RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
+                      1000, NULL);
+
+        while (1)
+        {
+            // uint16_t intr = 0;
+            // ctlwizchip(CW_GET_INTERRUPT, (void *)&intr);
+            // ir = (uint8_t)intr;
+            // sir = (uint8_t)((uint16_t)intr >> 8);
+
+            setIR(0xff); // 没有使用IR中断,保险起见进行清空
+
+            // 获取和处理套接字中断寄存器
+            sir = getSIR(); // 套接字中断寄存器
+            if (sir == 0)
+                break;
+
+            for (uint8_t socket = 0; socket < RyanW5500MaxSocketNum; socket++)
+            {
+                if (!(sir & (1 << socket))) // 判断是否当前socket通道中断
+                    continue;
+
+                // setSIR(socket); // 清除当前socket中断  setSn_IR时w5500内部会自动清除
+                // Sn_IR_SENDOK Sn_IR_TIMEOUT wiz官方库有使用,这里不使用
+                sn_ir = getSn_IR(socket);         // 获取中断类型消息
+                setSn_IR(socket, RyanW5500SnIMR); // 清除中断类型消息
+
+                if (sn_ir & Sn_IR_RECV) // 接收到了对方数据
+                {
+                    RyanW5500RecvDataCallback(socket);
+                    LOG_D("接收到数据");
+                }
+
+                if (sn_ir & Sn_IR_DISCON) // 当接收到对方的 FIN or FIN/ACK 包时
+                {
+                    RyanW5500CloseCallback(socket);
+                    LOG_D("断开连接");
+                }
+
+                if (sn_ir & Sn_IR_CON) // 成功与对方建立连接
+                {
+                    LOG_D("连接成功");
+                    RyanW5500Socket *sock = RyanW5500GetSock(socket);
+                    if (-1 == sock->serviceSocket)
+                        continue;
+
+                    RyanW5500Socket *serviceSock = RyanW5500GetSock(sock->serviceSocket);
+                    if (RyanW5500SocketListen != serviceSock->state || sock->port != serviceSock->port)
+                        continue;
+
+                    RyanListenServiceAddClient(serviceSock, sock);
+                }
+            }
+        }
+    }
+}
+
+int RyanW5500Init(wiz_NetInfo *netInfo)
+{
+
+    struct netdev *netdev = NULL;
+    memcpy(&gWIZNETINFO, netInfo, sizeof(wiz_NetInfo));
+    memset(&RyanW5500Entry, 0, sizeof(RyanW5500Entry));
+
+    RyanW5500Reset(); // 重启w5500
+
+    // 超时中断触发为retry_cnt * time_100us * 100us
+    struct wiz_NetTimeout_t net_timeout = {
+        .retry_cnt = 5,      // 重试次数
+        .time_100us = 2000}; // 200ms认为失败
+    ctlnetwork(CN_SET_TIMEOUT, (void *)&net_timeout);
+
+    // 检查w5500连接是否正常
+    memset(&net_timeout, 0, sizeof(struct wiz_NetTimeout_t));
+    ctlnetwork(CN_GET_TIMEOUT, (void *)&net_timeout);
+    if (0 == net_timeout.retry_cnt || 0 == net_timeout.time_100us)
+    {
+        LOG_E("Wiznet chip not detected");
+        return -1;
+    }
+
+    netdev = RyanW5500NetdevRegister("RyanW5500"); // W5500
+    netdev_low_level_set_status(netdev, RT_TRUE);  // 设置网络接口设备状态
+
+    RyanW5500Entry.W5500SpiMutexHandle = rt_mutex_create("RyanW5500SpiMutex", RT_IPC_FLAG_FIFO);
+    RyanW5500Entry.socketMutexHandle = rt_mutex_create("RyanW5500SocketMutex", RT_IPC_FLAG_FIFO);
+    RyanW5500Entry.W5500EventHandle = rt_event_create("RyanW5500Event", RT_IPC_FLAG_PRIO);
+
+    RyanW5500SpiInit();                                                     // w5500 spi初始化
+    reg_wizchip_cris_cbfunc(RyanW5500CriticalEnter, RyanW5500CriticalExit); // 注册临界区函数
+    reg_wizchip_cs_cbfunc(RyanW5500CsSelect, RyanW5500CsDeselect);          // 注册片选函数
+    reg_wizchip_spi_cbfunc(RyanW5500ReadByte, RyanW5500WriteByte);          // 注册读写函数
+    reg_wizchip_spiburst_cbfunc(RyanW5500ReadBurst, RyanW5500WriteBurst);   // 注册多个字节读写
+
+    RyanW5500AttachIRQ(RyanW5500IRQCallback); // 绑定w5500中断回调函数
+
+    RyanW5500Entry.w5500TaskHandle = rt_thread_create("RyanW5500",    // 线程name
+                                                      wizIntDataTask, // 线程入口函数
+                                                      (void *)netdev, // 线程入口函数参数
+                                                      1024,           // 线程栈大小
+                                                      8,              // 线程优先级
+                                                      5);             // 线程时间片
+
+    if (RyanW5500Entry.w5500TaskHandle != NULL)
+        rt_thread_startup(RyanW5500Entry.w5500TaskHandle);
+}

+ 25 - 0
W5500Client/RyanW5500.h

@@ -0,0 +1,25 @@
+
+#ifndef __RyanW5500__
+#define __RyanW5500__
+
+#include "wizchip_conf.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+    // 定义枚举类型
+    extern dhcp_mode;
+
+    // 定义结构体类型
+    extern wiz_NetInfo;
+
+    /* extern variables-----------------------------------------------------------*/
+    extern void RyanW5500Reset(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 220 - 0
W5500Client/RyanW5500Ping.c

@@ -0,0 +1,220 @@
+#define DBG_ENABLE
+
+#define DBG_SECTION_NAME ("RyanW5500Ping")
+#define DBG_LEVEL LOG_LVL_INFO
+#define DBG_COLOR
+
+#include "RyanW5500Store.h"
+
+#define Sn_PROTO(ch) (0x001408 + (ch << 5))
+
+#define WIZ_PING_DATA_LEN 32
+#define WIZ_PING_HEAD_LEN 8
+
+#define WIZ_PING_PORT 3000
+#define WIZ_PING_REQUEST 8
+#define WIZ_PING_REPLY 0
+#define WIZ_PING_CODE 0
+#define WIZ_PING_DELAY (1000)
+#define WIZ_PING_TIMEOUT (2000)
+
+struct wiz_ping_msg
+{
+    uint8_t type;                   // 0 - Ping Reply, 8 - Ping Request
+    uint8_t code;                   // Always 0
+    uint16_t check_sum;             // Check sum
+    uint16_t id;                    // Identification
+    uint16_t seq_num;               // Sequence Number
+    int8_t data[WIZ_PING_DATA_LEN]; // Ping Data  : 1452 = IP RAW MTU - sizeof(type+code+check_sum+id+seq_num)
+};
+
+/**
+ * @brief 计算字符串校验值
+ *
+ * @param src
+ * @param len
+ * @return uint16_t
+ */
+static uint16_t wiz_checksum(uint8_t *src, uint32_t len)
+{
+    uint16_t sum, tsum, i, j;
+    uint32_t lsum;
+
+    j = len >> 1;
+    lsum = 0;
+
+    for (i = 0; i < j; i++)
+    {
+        tsum = src[i * 2];
+        tsum = tsum << 8;
+        tsum += src[i * 2 + 1];
+        lsum += tsum;
+    }
+
+    if (len % 2)
+    {
+        tsum = src[i * 2];
+        lsum += (tsum << 8);
+    }
+
+    sum = lsum;
+    sum = ~(sum + (lsum >> 16));
+    return (uint16_t)sum;
+}
+
+static int wiz_ping_request(int socket)
+{
+    int idx, send_len;
+    uint16_t tmp_checksum;
+    struct wiz_ping_msg ping_req;
+
+    // 设置请求ping消息对象
+    ping_req.type = WIZ_PING_REQUEST;
+    ping_req.code = WIZ_PING_CODE;
+    ping_req.id = htons(rand() % 0xffff);
+    ping_req.seq_num = htons(rand() % 0xffff);
+    for (idx = 0; idx < WIZ_PING_DATA_LEN; idx++)
+        ping_req.data[idx] = (idx) % 8;
+
+    ping_req.check_sum = 0;
+    // 计算请求ping消息校验值
+    tmp_checksum = wiz_checksum((uint8_t *)&ping_req, sizeof(ping_req));
+    ping_req.check_sum = htons(tmp_checksum);
+
+    // 发送请求ping消息
+    send_len = wiz_send(socket, &ping_req, sizeof(ping_req), 0);
+    if (send_len != sizeof(ping_req))
+        return -1;
+
+    return send_len - WIZ_PING_HEAD_LEN;
+}
+
+static int wiz_ping_reply(int socket, struct sockaddr *from)
+{
+    uint16_t tmp_checksum;
+    uint8_t recv_buf[WIZ_PING_HEAD_LEN + WIZ_PING_DATA_LEN + 1];
+    struct wiz_ping_msg ping_rep;
+
+    int recv_len;
+    int idx;
+
+    platformTimer_t pingReplyTimer = {0};
+    platformTimerCutdown(&pingReplyTimer, WIZ_PING_TIMEOUT);
+    while (1)
+    {
+        if (0 == platformTimerRemain(&pingReplyTimer))
+            return -1;
+
+        struct sockaddr *sin = (struct sockaddr *)from;
+        socklen_t addr_len = sizeof(struct sockaddr_in);
+        recv_len = wiz_recvfrom(socket, recv_buf, WIZ_PING_HEAD_LEN + WIZ_PING_DATA_LEN, 0, sin, &addr_len);
+        if (recv_len < 0)
+            return -1;
+        break;
+    }
+
+    switch (recv_buf[0])
+    {
+    case WIZ_PING_REPLY:
+        ping_rep.type = recv_buf[0];
+        ping_rep.code = recv_buf[1];
+        ping_rep.check_sum = (recv_buf[3] << 8) + recv_buf[2];
+        ping_rep.id = (recv_buf[5] << 8) + recv_buf[4];
+        ping_rep.seq_num = (recv_buf[7] << 8) + recv_buf[6];
+        for (idx = 0; idx < recv_len - 8; idx++)
+            ping_rep.data[idx] = recv_buf[8 + idx];
+
+        tmp_checksum = ~wiz_checksum(recv_buf, recv_len);
+        if (tmp_checksum != 0xffff)
+            return -2;
+
+        break;
+
+    case WIZ_PING_REQUEST:
+        ping_rep.code = recv_buf[1];
+        ping_rep.type = recv_buf[2];
+        ping_rep.check_sum = (recv_buf[3] << 8) + recv_buf[2];
+        ping_rep.id = (recv_buf[5] << 8) + recv_buf[4];
+        ping_rep.seq_num = (recv_buf[7] << 8) + recv_buf[6];
+        for (idx = 0; idx < recv_len - 8; idx++)
+            ping_rep.data[idx] = recv_buf[8 + idx];
+
+        tmp_checksum = ping_rep.check_sum;
+        ping_rep.check_sum = 0;
+        if (tmp_checksum != ping_rep.check_sum)
+            return -2;
+
+        break;
+
+    default:
+        LOG_W("unknown ping receive message.");
+        return -1;
+    }
+
+    return recv_len - WIZ_PING_HEAD_LEN;
+}
+
+int RyanW5500Ping(struct netdev *netdev, const char *host, size_t data_len, uint32_t times, struct netdev_ping_resp *ping_resp)
+{
+    int result = 0,
+        socket = 0;
+    struct hostent *hostent = NULL;
+
+    hostent = wiz_gethostbyname(host);
+    if (NULL == hostent || NULL == hostent->h_addr_list[0])
+    {
+        LOG_W("hostent is NULL.");
+        return -RT_FALSE;
+    }
+
+    struct in_addr serviceAddr = *(struct in_addr *)hostent->h_addr_list[0];
+
+    // SOCK_RAW == Sn_MR_IPRAW == 3
+    socket = wiz_socket(AF_WIZ, SOCK_RAW, 0);
+    if (socket < 0)
+    {
+        LOG_W("create ping socket(%d) failed.", socket);
+        return -1;
+    }
+
+    // 设置套接字ICMP协议
+    IINCHIP_WRITE(Sn_PROTO(socket), IPPROTO_ICMP);
+
+    struct timeval timeout = {.tv_sec = times,
+                              .tv_usec = times % 1000 * 1000};
+
+    // 设置接收和发送超时选项
+    wiz_setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout,
+                   sizeof(timeout));
+
+    wiz_setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (void *)&timeout,
+                   sizeof(timeout));
+
+    struct sockaddr_in server_addr = {.sin_family = AF_WIZ,
+                                      .sin_port = htons(WIZ_PING_PORT),
+                                      .sin_addr = serviceAddr};
+
+    if (wiz_connect(socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
+    {
+        wiz_closesocket(socket);
+        return -1;
+    }
+
+    result = wiz_ping_request(socket);
+
+    platformTimer_t pingTimer = {0};
+    platformTimerCutdown(&pingTimer, 0xffff);
+    if (result > 0)
+    {
+        result = wiz_ping_reply(socket, (struct sockaddr *)&server_addr);
+
+        ping_resp->ip_addr.addr = serviceAddr.s_addr;
+        ping_resp->ticks = 0xffff - platformTimerRemain(&pingTimer);
+        ping_resp->data_len = data_len;
+        wiz_getsockopt(socket, IPPROTO_IP, IP_TTL, &ping_resp->ttl, sizeof(ping_resp->ttl));
+    }
+
+    wiz_closesocket(socket);
+
+    return result;
+}

+ 23 - 0
W5500Client/RyanW5500Ping.h

@@ -0,0 +1,23 @@
+#ifndef __RyanW5500Ping__
+#define __RyanW5500Ping__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "RyanW5500Store.h"
+
+    // 定义枚举类型
+
+    // 定义结构体类型
+
+    /* extern variables-----------------------------------------------------------*/
+    extern int RyanW5500Ping(struct netdev *netdev, const char *host, size_t data_len,
+                             uint32_t times, struct netdev_ping_resp *ping_resp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 1491 - 0
W5500Client/RyanW5500Socket.c

@@ -0,0 +1,1491 @@
+#define DBG_ENABLE
+
+#define DBG_SECTION_NAME ("RyanW5500Socket")
+#define DBG_LEVEL LOG_LVL_INFO
+#define DBG_COLOR
+
+#include "RyanW5500Store.h"
+
+#define RyanW5500LinkCheck(value)               \
+    do                                          \
+    {                                           \
+        uint8_t linkState = 0;                  \
+        ctlwizchip(CW_GET_PHYLINK, &linkState); \
+        if (PHY_LINK_ON != linkState)           \
+            return -1;                          \
+    } while (0);
+
+// 可用套接字的全局数组
+static RyanW5500Socket RyanW5500Sockets[RyanW5500MaxSocketNum] = {0};
+static uint16_t wiz_port = 5500; // 用户可以自定义
+
+/**
+ * @brief 中断接收到数据回调函数
+ *
+ * @param socket
+ * @return int
+ */
+int RyanW5500RecvDataCallback(int socket)
+{
+    RyanW5500Socket *sock = NULL;
+
+    sock = RyanW5500GetSock(socket);
+    RyanW5500CheckCode(NULL != sock, EBADF, { return -1; });
+
+    rt_event_send(RyanW5500Entry.W5500EventHandle, 1 << sock->socket);
+
+    return 0;
+}
+
+/**
+ * @brief 中断接收到close信号回调函数
+ *
+ * @param socket
+ * @return int
+ */
+int RyanW5500CloseCallback(int socket)
+{
+    RyanW5500Socket *sock = NULL;
+
+    sock = RyanW5500GetSock(socket);
+    RyanW5500CheckCode(NULL != sock, EBADF, { return -1; });
+
+    sock->state = RyanW5500SocketClose;
+    rt_event_send(RyanW5500Entry.W5500EventHandle, 1 << sock->socket);
+
+    return 0;
+}
+
+/**
+ * @brief
+ *
+ * @param s_addr
+ * @param ipStrArr
+ */
+void inAddrToipStrArr(in_addr_t *s_addr, uint8_t *ipStrArr)
+{
+    assert(NULL != s_addr);
+    assert(NULL != ipStrArr);
+
+    // inet_pton(AF_INET, inet_ntoa(sin->sin_addr), &ipStrArr); // 效率有点低
+    uint8_t *p = (uint8_t *)s_addr;
+    ipStrArr[0] = *p;
+    ipStrArr[1] = *(p + 1);
+    ipStrArr[2] = *(p + 2);
+    ipStrArr[3] = *(p + 3);
+}
+
+/**
+ * @brief
+ *
+ * @param ipStrArr
+ * @return in_addr_t
+ */
+in_addr_t ipStrArrToinAddr(uint8_t *ipStrArr)
+{
+
+    assert(NULL != ipStrArr);
+
+    // 效率有点低
+    // char remote_ipaddr[16] = {0};
+    // snprintf(remote_ipaddr, sizeof(remote_ipaddr), "%d.%d.%d.%d", ipStrArr[0], ipStrArr[1], ipStrArr[2], ipStrArr[3]);
+    // return inet_addr((const char *)remote_ipaddr);
+
+    in_addr_t p2 = 0;
+    uint8_t *p = (uint8_t *)&p2;
+    *p = ipStrArr[0];
+    *(p + 1) = ipStrArr[1];
+    *(p + 2) = ipStrArr[2];
+    *(p + 3) = ipStrArr[3];
+    return p2;
+}
+
+/**
+ * @brief 根据socket获取RyanW5500Socket结构体
+ *
+ * @param socket
+ * @return RyanW5500Socket*
+ */
+RyanW5500Socket *RyanW5500GetSock(int socket)
+{
+    if (socket < 0 || socket >= RyanW5500MaxSocketNum)
+        return NULL;
+
+    // 检查套接字结构是否有效
+    if (RyanW5500Sockets[socket].magic != WIZ_SOCKET_MAGIC)
+        return NULL;
+
+    return &RyanW5500Sockets[socket];
+}
+
+static int RyanW5500SocketDestory(RyanW5500Socket *sock)
+{
+
+    assert(NULL != sock);
+
+    rt_mutex_take(RyanW5500Entry.socketMutexHandle, RT_WAITING_FOREVER); // 获取互斥锁
+    if (sock->remoteAddr)
+        free(sock->remoteAddr);
+
+    // 是服务器套接字,释放服务器信息并关闭所有客户端套接字clientList
+    if (sock->serviceInfo)
+    {
+        RyanW5500ClientInfo *clientInfo = NULL;
+
+        // 分配并初始化新的客户端套接字
+        RyanList_t *curr = NULL,
+                   *next = NULL;
+        RyanW5500ClientInfo *clientHandler = NULL;
+
+        RyanListForEachSafe(curr, next, &sock->serviceInfo->clientList)
+        {
+            // 获取此节点的结构体
+            clientInfo = RyanListEntry(curr, RyanW5500ClientInfo, list);
+            if (NULL == clientInfo)
+                continue;
+
+            RyanListDel(&clientInfo->list);
+            wiz_closesocket(clientInfo->sock->socket);
+            free(clientInfo);
+        }
+
+        if (sock->serviceInfo->clientInfoQueueHandle)
+            rt_mq_delete(sock->serviceInfo->clientInfoQueueHandle);
+
+        if (sock->serviceInfo)
+            free(sock->serviceInfo);
+    }
+    else if (-1 != sock->serviceSocket) // 可能是listen客户端套接字,根据记录的serviceSocket判断是否为listen客户端
+    {
+        RyanW5500Socket *serviceSock = RyanW5500GetSock(sock->serviceSocket);
+        if (NULL != serviceSock->serviceInfo && sock->port == serviceSock->port)
+        {
+
+            // 分配并初始化新的客户端套接字
+            RyanList_t *curr = NULL,
+                       *next = NULL;
+            RyanW5500ClientInfo *clientInfo = NULL;
+
+            RyanListForEachSafe(curr, next, &serviceSock->serviceInfo->clientList)
+            {
+                // 获取此节点的结构体
+                clientInfo = RyanListEntry(curr, RyanW5500ClientInfo, list);
+                if (NULL == clientInfo || clientInfo->sock->socket != sock->socket)
+                    continue;
+
+                RyanListDel(&clientInfo->list);
+
+                // 添加服务器套接字监听数
+                serviceSock->serviceInfo->backlog++;
+                free(clientInfo);
+                break;
+            }
+        }
+    }
+
+    setSn_IR(sock->socket, 0xff); // 清空套接字中断
+    setSn_IMR(sock->socket, 0);   // 设置套接字ISR状态支持
+    memset(sock, 0, sizeof(RyanW5500Socket));
+    rt_mutex_release(RyanW5500Entry.socketMutexHandle); // 释放互斥锁
+    return 0;
+}
+
+/**
+ * @brief 创建socket
+ *
+ * @param type
+ * @param port
+ * @return RyanW5500Socket*
+ */
+RyanW5500Socket *RyanW5500SocketCreate(int type, int port)
+{
+
+    RyanW5500Socket *sock = NULL;
+    char name[32] = {0};
+    int idx = 0;
+
+    rt_mutex_take(RyanW5500Entry.socketMutexHandle, RT_WAITING_FOREVER); // 获取互斥锁
+    // 找到一个空的 WIZnet 套接字条目
+    for (idx = 0; idx < RyanW5500MaxSocketNum && RyanW5500Sockets[idx].magic; idx++)
+        ;
+
+    // 没有空闲socket
+    RyanW5500CheckCode(RyanW5500MaxSocketNum != idx, EMFILE, { goto err; });
+
+    sock = &(RyanW5500Sockets[idx]);
+    sock->magic = WIZ_SOCKET_MAGIC;
+    sock->socket = idx;
+    sock->type = type;
+    sock->port = port;
+    sock->state = RyanW5500SocketInit;
+    sock->remoteAddr = NULL;
+    sock->recvTimeout = 0;
+    sock->sendTimeout = 0;
+    sock->serviceInfo = NULL; // 用于服务器套接字
+    sock->serviceSocket = -1;
+
+    rt_mutex_release(RyanW5500Entry.socketMutexHandle); // 释放互斥锁
+
+    setSn_IR(sock->socket, 0xff);            // 清空套接字中断
+    setSn_IMR(sock->socket, RyanW5500SnIMR); // 设置套接字ISR状态支持
+
+    int8_t result = wizchip_socket(sock->socket, sock->type, sock->port, 0); // wizchip_socket内部会先close一次
+    if (result != sock->socket)
+    {
+        LOG_E("RyanW5500 socket(%d) create failed!  result: %d", sock->socket, result);
+        goto err;
+    }
+
+    return sock;
+
+err:
+    rt_mutex_release(RyanW5500Entry.socketMutexHandle); // 释放互斥锁
+    wiz_closesocket(sock->socket);
+    return NULL;
+}
+
+/**
+ * @brief 给listen服务器套接字创建client客户端
+ *
+ * @param serviceSock
+ * @return RyanW5500Socket*
+ */
+RyanW5500Socket *RyanW5500CreateListenClient(RyanW5500Socket *serviceSock)
+{
+    assert(NULL != serviceSock);
+
+    RyanW5500Socket *clientSock = NULL;
+    clientSock = RyanW5500SocketCreate(serviceSock->type, serviceSock->port);
+    RyanW5500CheckCode(NULL != clientSock, EMFILE, { goto err; });
+
+    clientSock->serviceSocket = serviceSock->socket;
+
+    // 创建客户端信息并将客户端添加到服务器clientList
+    RyanW5500ClientInfo *clientInfo = (RyanW5500ClientInfo *)malloc(sizeof(RyanW5500ClientInfo));
+    RyanW5500CheckCode(NULL != clientInfo, ENOMEM, { goto err; });
+    memset(clientInfo, 0, sizeof(RyanW5500ClientInfo));
+
+    clientInfo->sock = clientSock;
+    RyanListAddTail(&clientInfo->list, &serviceSock->serviceInfo->clientList);
+
+    RyanW5500CheckCode(SOCK_OK == wizchip_listen(clientSock->socket), EPROTO, {wiz_closesocket(clientSock->socket); goto err; });
+    clientSock->state = RyanW5500SocketListen;
+
+    return clientSock;
+err:
+    if (NULL != clientInfo)
+        wiz_closesocket(clientSock->socket);
+
+    if (NULL != clientInfo)
+        free(clientInfo);
+    return NULL;
+}
+
+/**
+ * @brief 新的listen客户端连接
+ *
+ * @param serviceSock
+ * @param clientSock
+ */
+void RyanListenServiceAddClient(RyanW5500Socket *serviceSock, RyanW5500Socket *clientSock)
+{
+
+    assert(NULL != serviceSock);
+    assert(NULL != clientSock);
+
+    int8_t socket = -1;
+
+    // 检查服务器侦听积压工作编号
+    if (serviceSock->serviceInfo->backlog <= 0)
+        goto err;
+
+    serviceSock->serviceInfo->backlog--;
+    clientSock->state = RyanW5500SocketEstablished;
+
+    // 发送客户端套接字连接消息和事件
+    socket = clientSock->socket;
+    rt_mq_send(serviceSock->serviceInfo->clientInfoQueueHandle, &socket, sizeof(int8_t));
+
+    RyanW5500Socket *sock = RyanW5500CreateListenClient(serviceSock);
+    if (NULL == sock)
+        goto err;
+
+    return;
+
+err:
+    socket = -1;
+    rt_mq_send(serviceSock->serviceInfo->clientInfoQueueHandle, &socket, sizeof(int8_t));
+}
+
+/**
+ * @brief 创建套接字
+ *
+ * @param domain 协议族类型
+ * @param type 协议类型
+ * @param protocol 实际使用的运输层协议
+ * @return int 返回一个代表套接字描述符的整数
+ */
+int wiz_socket(int domain, int type, int protocol)
+{
+    RyanW5500LinkCheck(-1);
+
+    RyanW5500Socket *sock = NULL;
+
+    // 该实现不支持指定的协议族类型。
+    RyanW5500CheckCode(AF_INET == domain || AF_WIZ == domain, EAFNOSUPPORT, { return -1; });
+    // 不支持特定的运输层协议
+    RyanW5500CheckCode(0 == protocol, EPROTONOSUPPORT, { return -1; });
+
+    switch (type)
+    {
+    case SOCK_STREAM:
+    case SOCK_DGRAM:
+    case SOCK_RAW:
+        break;
+
+    default:
+        // 协议不支持套接字类型
+        RyanW5500CheckCode(NULL, EPROTOTYPE, { return -1; });
+    }
+
+    // 分配并初始化一个新的 WIZnet 套接字
+    sock = RyanW5500SocketCreate(type, wiz_port);
+    RyanW5500CheckCode(NULL != sock, EMFILE, { return -1; });
+
+    sock->state = RyanW5500SocketInit;
+    wiz_port++;
+
+    return sock->socket;
+}
+
+/**
+ * @brief 该函数用于将端口号和 IP 地址绑定带指定套接字上。
+ *
+ * @param socket 套接字描述符
+ * @param name 指向 sockaddr 结构体的指针
+ * @param namelen sockaddr 结构体的长度
+ * @return int
+ */
+int wiz_bind(int socket, const struct sockaddr *name, socklen_t namelen)
+{
+
+    RyanW5500LinkCheck(-1);
+
+    RyanW5500Socket *sock = NULL;
+    uint16_t port = 0;
+    ip_addr_t ipaddr = {0};
+
+    RyanW5500CheckCode(NULL != name && 0 != namelen, EAFNOSUPPORT, { return -1; }); // 非法地址
+
+    sock = RyanW5500GetSock(socket);
+    RyanW5500CheckCode(NULL != sock, EBADF, { return -1; });
+
+    // PRASE IP 地址和端口
+    const struct sockaddr_in *sin = (const struct sockaddr_in *)name;
+    ipaddr.addr = sin->sin_addr.s_addr;
+    port = (uint16_t)htons(sin->sin_port);
+
+    if (sock->port == port)
+        return 0;
+
+    sock->port = port;
+    // wizchip_socket内部会先close一次
+    int8_t result = wizchip_socket(sock->socket, sock->type, sock->port, 0);
+    RyanW5500CheckCode(result == sock->socket, EMFILE, { return -1; });
+
+    sock->state = RyanW5500SocketInit;
+
+    return 0;
+}
+
+/**
+ * @brief 建立连接
+ *
+ * @param socket 套接字描述符
+ * @param name 服务器地址信息
+ * @param namelen 服务器地址结构体的长度
+ * @return int
+ */
+int wiz_connect(int socket, const struct sockaddr *name, socklen_t namelen)
+{
+    RyanW5500LinkCheck(-1);
+    RyanW5500CheckCode(NULL != name && 0 != namelen, EAFNOSUPPORT, { return -1; }); // 非法地址
+
+    RyanW5500Socket *sock = NULL;
+    ip_addr_t remoteAddr;
+
+    sock = RyanW5500GetSock(socket);
+    RyanW5500CheckCode(NULL != sock, EBADF, { return -1; });
+    RyanW5500CheckCode(RyanW5500SocketInit == sock->state, EADDRINUSE, { return -1; }); // 尝试建立 已在使用的 / 未初始化 socket的连接。
+
+    switch (getSn_SR(socket))
+    {
+    case SOCK_UDP: // udp
+    case SOCK_IPRAW:
+        if (NULL == sock->remoteAddr)
+        {
+            sock->remoteAddr = (struct sockaddr *)malloc(sizeof(struct sockaddr));
+            RyanW5500CheckCode(NULL != sock->remoteAddr, ENOMEM, { return -1; });
+            memset(sock->remoteAddr, 0, sizeof(struct sockaddr));
+        }
+
+        // 复制远程端口,ip,协议族
+        sock->remoteAddr->sa_len = name->sa_len;
+        sock->remoteAddr->sa_family = name->sa_family;
+        memcpy(sock->remoteAddr->sa_data, name->sa_data, sizeof(sock->remoteAddr->sa_data));
+        break;
+
+    case SOCK_INIT: // tcp
+                    // 通过套接字结构获取 IP 地址和端口
+    {
+        uint8_t ipStrArr[4] = {0};
+        const struct sockaddr_in *sin = (const struct sockaddr_in *)name;
+
+        inAddrToipStrArr(&sin->sin_addr.s_addr, ipStrArr);
+
+        int result = wizchip_connect(socket, ipStrArr, htons(sin->sin_port));
+        if (SOCK_OK != result)
+        {
+            RyanW5500CheckCode(SOCKERR_IPINVALID != result, EAFNOSUPPORT, { return -1; }); // 无效的 IP 地址
+            RyanW5500CheckCode(SOCKERR_TIMEOUT != result, ETIMEDOUT, { return -1; });      // 连接超时
+            return -1;
+        }
+    }
+
+    break;
+
+    default:
+        break;
+    }
+
+    sock->state = RyanW5500SocketEstablished;
+    return 0;
+}
+
+/**
+ * @brief 监听套接字
+ *
+ * @param socket 套接字描述符
+ * @param backlog 表示一次能够等待的最大连接数目
+ * @return int
+ */
+int wiz_listen(int socket, int backlog)
+{
+    RyanW5500LinkCheck(-1);
+
+    RyanW5500Socket *sock = NULL;
+    sock = RyanW5500GetSock(socket);
+
+    RyanW5500CheckCode(NULL != sock, EBADF, { return -1; });                               // 套接字参数不是有效的文件描述符。
+    RyanW5500CheckCode(RyanW5500SocketEstablished != sock->state, EINVAL, { return -1; }); // 套接字已连接
+    RyanW5500CheckCode(Sn_MR_IPRAW != sock->type, EOPNOTSUPP, { return -1; });             // 套接字协议不支持 listen()
+    RyanW5500CheckCode(NULL == sock->serviceInfo, EINVAL, { return -1; });                 // 套接字第一次调用listen
+
+    sock->serviceInfo = (RyanW5500ServiceInfo *)malloc(sizeof(RyanW5500ServiceInfo));
+    RyanW5500CheckCode(NULL != sock->serviceInfo, ENOMEM, { goto err; });
+    memset(sock->serviceInfo, 0, sizeof(RyanW5500ServiceInfo));
+
+    // 创建客户端套接字连接事件邮箱
+    char name[32] = {0};
+    snprintf(name, 32, "wiz_mb%d", sock->socket);
+    sock->serviceInfo->backlog = backlog > 0 ? backlog : 0;
+
+    // BSD socket允许listen队列为0,这里消息队列创建1大小,为了appect是可以阻塞
+    sock->serviceInfo->clientInfoQueueHandle = rt_mq_create(name, sizeof(int8_t), backlog > 0 ? backlog : 1, RT_IPC_FLAG_FIFO);
+    RyanW5500CheckCode(NULL != sock->serviceInfo->clientInfoQueueHandle, ENOMEM, { goto err; });
+
+    RyanListInit(&sock->serviceInfo->clientList);
+    sock->state = RyanW5500SocketListen;
+
+    RyanW5500CreateListenClient(sock);
+
+    return 0;
+
+err:
+    if (NULL != sock->serviceInfo)
+    {
+        if (NULL != sock->serviceInfo->clientInfoQueueHandle)
+            rt_mq_delete(sock->serviceInfo->clientInfoQueueHandle);
+        free(sock->serviceInfo);
+        sock->serviceInfo = NULL;
+    }
+
+    return -1;
+}
+
+/**
+ * @brief 接收连接
+ *
+ * @param socket 套接字描述符
+ * @param addr 存储客户端设备地址结构体
+ * @param addrlen 客户端设备地址结构体的长度
+ * @return int
+ */
+int wiz_accept(int socket, struct sockaddr *addr, socklen_t *addrlen)
+{
+    RyanW5500LinkCheck(-1);
+    RyanW5500Socket *serviceSock = NULL;
+    int8_t clientSocket = -1;
+
+    RyanW5500CheckCode(NULL != addr && 0 != addrlen, EAFNOSUPPORT, { return -1; }); // 非法地址
+
+    serviceSock = RyanW5500GetSock(socket);
+
+    RyanW5500CheckCode(NULL != serviceSock, EBADF, { return -1; });                          // 套接字参数不是有效的文件描述符。
+    RyanW5500CheckCode(RyanW5500SocketListen == serviceSock->state, EINVAL, { return -1; }); // 套接字不接受连接,没有listen
+    RyanW5500CheckCode(NULL != serviceSock->serviceInfo, ENOBUFS, { return -1; });           // 没有可用的缓冲区空间,理论上不会出现
+
+    while (1)
+    {
+        // 接收客户端连接消息
+        if (rt_mq_recv(serviceSock->serviceInfo->clientInfoQueueHandle, (void *)&clientSocket, sizeof(int8_t), RT_WAITING_FOREVER) != RT_EOK)
+            continue;
+
+        RyanW5500CheckCode(-1 != clientSocket, EPROTO, { return -1; });
+
+        // 检查连接消息类型
+        if (SOCK_ESTABLISHED != getSn_SR(clientSocket))
+        {
+            // 错误按摩,关闭客户端套接字
+            wiz_closesocket(clientSocket);
+            RyanW5500CheckCode(NULL, EPROTO, { return -1; }); // 发生协议错误,客户端套接字不处于连接状态,极端情况才会出现
+        }
+
+        // 获取新的客户端套接字信息
+        struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+        uint8_t ipStrArr[4] = {0};
+        uint16_t remotePort = getSn_DPORT(clientSocket);
+        getSn_DIPR(clientSocket, ipStrArr); // 获取远程 IP 地址和端口
+
+        memset(sin, 0, sizeof(struct sockaddr_in));
+        sin->sin_port = htons(remotePort);
+        sin->sin_addr.s_addr = ipStrArrToinAddr(ipStrArr);
+
+        *addrlen = sizeof(struct sockaddr);
+        LOG_D("remote ip: %s, remote port: %d", inet_ntoa(sin->sin_addr.s_addr), remotePort);
+
+        return clientSocket;
+    }
+}
+
+/**
+ * @brief
+ *
+ * @param socket 套接字描述符
+ * @param data 发送的消息的缓冲区
+ * @param size 以字节为单位消息的大小
+ * @param flags 消息传输的类型,一般为 0
+ * @param to 指向包含目标地址的sockaddr结构
+ * @param tolen 指向的sockaddr结构的长度
+ * @return int 返回发送的字节数
+ */
+int wiz_sendto(int socket, const void *data, size_t size, int flags, const struct sockaddr *to, socklen_t tolen)
+{
+    RyanW5500LinkCheck(-1);
+    RyanW5500Socket *sock = NULL;
+    uint8_t socketState = 0;
+    int32_t sendLen = 0,
+            timeout = 0,
+            result = 0;
+
+    RyanW5500CheckCode(NULL != data && 0 != size, EFAULT, { return -1; });
+
+    sock = RyanW5500GetSock(socket);
+    RyanW5500CheckCode(NULL != sock, EBADF, { return -1; });
+
+    timeout = sock->sendTimeout;
+    if (timeout <= 0)
+        timeout = RT_WAITING_FOREVER;
+
+    // 设置接收超时
+    platformTimer_t recvTimer = {0};
+    platformTimerCutdown(&recvTimer, timeout);
+
+    switch (sock->type)
+    {
+    case Sn_MR_TCP:
+        socketState = getSn_SR(socket);
+        RyanW5500CheckCode(SOCK_ESTABLISHED == socketState, EDESTADDRREQ, { return -1; }); // 套接字不是连接模式,没有设置其对等地址,也没有指定目标地址。
+
+        // 如果发送数据比剩余缓冲区大,则分片发送,否则缓冲区数据会被清空
+        sendLen = getSn_TX_FSR(sock->socket);
+        RyanW5500CheckCode(0 <= sendLen, EWOULDBLOCK, { return -1; }); // 发送缓冲区已满
+
+        sendLen = sendLen > size ? size : sendLen;
+        sendLen = wizchip_send(socket, (uint8_t *)data, sendLen);
+        RyanW5500CheckCode(sendLen >= 0, EINTR, { return -1; }); // 发送失败,一般不会,所以将错误设置为信号中断
+        break;
+
+    case Sn_MR_UDP:
+    case Sn_MR_IPRAW:
+    {
+
+        socketState = getSn_SR(socket);
+        RyanW5500CheckCode(SOCK_UDP == socketState || SOCK_IPRAW == socketState, EDESTADDRREQ, { return -1; });
+
+        struct sockaddr_in *sin = NULL;
+
+        // 获取目标地址结构体指针
+        if (RyanW5500SocketEstablished == sock->state && NULL != sock->remoteAddr)
+            sin = (const struct sockaddr_in *)sock->remoteAddr;
+        else
+            sin = (const struct sockaddr_in *)to;
+
+        // 查看是否是广播
+        if (sin->sin_addr.s_addr == -1) // inet_addr("255.255.255.255")
+            RyanW5500CheckCode(0 != (sock->soOptionsFlag & SO_BROADCAST), EACCES, { return -1; });
+
+        // 将发送ip转换为W5500识别的
+        uint8_t ipStrArr[4] = {0};
+        inAddrToipStrArr(&sin->sin_addr.s_addr, ipStrArr);
+
+        // 如果发送数据比剩余缓冲区大,则分片发送,否则缓冲区数据会被清空
+        sendLen = getSn_TX_FSR(sock->socket);
+        RyanW5500CheckCode(0 <= sendLen, EWOULDBLOCK, { return -1; }); // 发送缓冲区已满
+
+        sendLen = sendLen > size ? size : sendLen;
+        sendLen = wizchip_sendto(sock->socket, (uint8_t *)data, sendLen, ipStrArr, htons(sin->sin_port));
+        if (sendLen < 0)
+        {
+            RyanW5500CheckCode(SOCKERR_SOCKCLOSED == sendLen, EPIPE, { return -1; }); // 套接字被关闭
+            LOG_E("udp send fail, result: %d", sendLen);
+            return -1;
+        }
+
+        break;
+    }
+
+    default:
+        LOG_E("socket (%d) type %d is not support.", socket, sock->type);
+        return -1;
+    }
+
+    return sendLen;
+}
+
+/**
+ * @brief
+ *
+ * @param socket 套接字描述符
+ * @param mem 接收消息的缓冲区
+ * @param len 接收消息的缓冲区长度
+ * @param flags 消息接收的类型,一般为 0
+ * @param from 接收地址结构体指针,可以为NULL
+ * @param fromlen 接收地址结构体长度
+ * @return int 返回接收的数据的长度
+ */
+int wiz_recvfrom(int socket, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
+{
+    RyanW5500LinkCheck(-1);
+
+    RyanW5500Socket *sock = NULL;
+    uint8_t socketState = 0;
+    int32_t recvLen = 0,
+            timeout = 0,
+            result = 0;
+    platformTimer_t recvTimer = {0};
+
+    RyanW5500CheckCode(NULL != mem && 0 != len, EFAULT, { return -1; });
+
+    sock = RyanW5500GetSock(socket);
+    RyanW5500CheckCode(NULL != sock, EBADF, { return -1; });
+
+    // 设置 WIZNnet 套接字接收超时
+    timeout = sock->recvTimeout;
+    if (timeout <= 0)
+        timeout = RT_WAITING_FOREVER;
+
+    platformTimerCutdown(&recvTimer, timeout);
+
+again:
+    // 判断是否超时
+    RyanW5500CheckCode(0 != platformTimerRemain(&recvTimer), EAGAIN, { return -1; });
+
+    switch (sock->type)
+    {
+    case Sn_MR_TCP:
+    {
+
+        socketState = getSn_SR(socket);
+        RyanW5500CheckCode(SOCK_ESTABLISHED == socketState, ENOTCONN, { return -1; }); // 在未连接的连接模式套接字上尝试接收。
+
+        result = rt_event_recv(RyanW5500Entry.W5500EventHandle, (1 << sock->socket),
+                               RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
+                               timeout, NULL);
+        RyanW5500CheckCode(RT_EOK == result, EAGAIN, { return -1; });                        // 判断是否超时
+        RyanW5500CheckCode(RyanW5500SocketClose != sock->state, ECONNRESET, { return -1; }); // 连接被对等方关闭。
+
+        // 获取数据寄存器,没有数据就重新接收
+        recvLen = getSn_RX_RSR(socket);
+        if (recvLen <= 0)
+            goto again;
+
+        // 接收数据到用户缓冲区
+        recvLen = recvLen > len ? len : recvLen; // 如果数据比缓冲区大,则调整至缓冲区大小
+        recvLen = wizchip_recv(socket, mem, recvLen);
+        if (recvLen < 0)
+        {
+            LOG_E("recv error, result: %d", recvLen);
+            return -1;
+        }
+
+        break;
+    }
+
+    case Sn_MR_UDP:
+    case Sn_MR_IPRAW:
+    {
+        socketState = getSn_SR(socket);
+        RyanW5500CheckCode(SOCK_UDP == socketState || SOCK_IPRAW == socketState, ENOTCONN, { return -1; }); // 在未连接的连接模式套接字上尝试接收。
+
+        result = rt_event_recv(RyanW5500Entry.W5500EventHandle, (1 << sock->socket),
+                               RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
+                               timeout, NULL);
+        RyanW5500CheckCode(RT_EOK == result, EAGAIN, { return -1; }); // 判断是否超时
+        RyanW5500CheckCode(RyanW5500SocketClose != sock->state, ECONNRESET, { return -1; });
+
+        // 获取数据寄存器,没有数据就重新接收
+        recvLen = getSn_RX_RSR(socket);
+        if (recvLen <= 0)
+            goto again;
+
+        uint16_t remotePort = 0;
+        uint8_t remoteIp[4] = {0};
+
+        recvLen = recvLen > len ? len : recvLen;
+        recvLen = wizchip_recvfrom(socket, mem, recvLen, remoteIp, &remotePort);
+        if (recvLen < 0)
+        {
+            LOG_E("recvfrom error, result: %d", recvLen);
+            return -1;
+        }
+
+        // 将消息信息写入from结构体
+        *fromlen = sizeof(struct sockaddr_in);
+        struct sockaddr_in *sin = (struct sockaddr_in *)from;
+        memset(sin, 0, sizeof(struct sockaddr_in));
+
+        sin->sin_port = htons(remotePort);
+        sin->sin_addr.s_addr = ipStrArrToinAddr(remoteIp);
+        break;
+    }
+
+    default:
+        LOG_E("socket (%d) type %d is not support.", socket, sock->type);
+        return -1;
+    }
+
+    return recvLen;
+}
+
+int wiz_send(int socket, const void *data, size_t size, int flags)
+{
+    return wiz_sendto(socket, data, size, flags, NULL, 0);
+}
+
+/**
+ * @brief TCP 数据接收
+ *
+ * @param socket 套接字描述符
+ * @param mem 接收消息的缓冲区
+ * @param len 接收消息的缓冲区长度
+ * @param flags 消息接收的类型,一般为 0
+ * @return int
+ */
+int wiz_recv(int socket, void *mem, size_t len, int flags)
+{
+    return wiz_recvfrom(socket, mem, len, flags, NULL, NULL);
+}
+
+/**
+ * @brief 关闭套接字
+ *
+ * @param socket 套接字描述符
+ * @return int
+ */
+int wiz_closesocket(int socket)
+{
+    RyanW5500Socket *sock = NULL;
+
+    sock = RyanW5500GetSock(socket);
+    RyanW5500CheckCode(NULL != sock, EBADF, { return -1; });
+
+    if (SOCK_CLOSED == getSn_SR(sock->socket))
+    {
+        RyanW5500SocketDestory(sock);
+        return -1;
+    }
+
+    int8_t result = SOCK_FATAL;
+    if (Sn_MR_TCP == sock->type && NULL == sock->serviceInfo)
+        result = wizchip_disconnect(sock->socket);
+
+    if (SOCK_OK != result)
+    {
+        result = wizchip_close(sock->socket);
+        if (SOCK_OK != result)
+        {
+            LOG_E("socket(%d) close failed.", sock->socket);
+            RyanW5500SocketDestory(sock);
+            return -1;
+        }
+    }
+
+    return RyanW5500SocketDestory(sock);
+}
+
+/**
+ * @brief 按设置关闭套接字
+ *
+ * @param socket 套接字描述符
+ * @param how 套接字控制的方式
+ * @return int
+ */
+int wiz_shutdown(int socket, int how)
+{
+    RyanW5500Socket *sock = NULL;
+
+    switch (how)
+    {
+    case SHUT_RD:   // 禁用进一步的接收操作。
+    case SHUT_WR:   // 禁用进一步的发送操作。
+    case SHUT_RDWR: // 禁用进一步的发送和接收操作。
+        break;
+
+    default:
+        RyanW5500CheckCode(NULL, EINVAL, return -1;)
+    }
+
+    sock = RyanW5500GetSock(socket);
+    RyanW5500CheckCode(NULL != sock, EBADF, { return -1; });
+
+    return wiz_closesocket(sock->socket);
+}
+
+/**
+ * @brief 设置套接字选项
+ *
+ * @param socket 套接字描述符
+ * @param level 协议栈配置选项
+ * @param optname 需要设置的选项名
+ * @param optval 设置选项值的缓冲区地址
+ * @param optlen 设置选项值的缓冲区长度
+ * @return int
+ */
+int wiz_setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen)
+{
+    RyanW5500LinkCheck(-1);
+
+    RyanW5500Socket *sock = NULL;
+
+    RyanW5500CheckCode(NULL != optval && 0 != optlen, EFAULT, { return -1; });
+
+    sock = RyanW5500GetSock(socket);
+    RyanW5500CheckCode(NULL != sock, EBADF, { return -1; }); // 指定的选项在指定的套接字级别无效或套接字已关闭。
+
+    if (SOL_SOCKET == level)
+    {
+        switch (optname)
+        {
+        case SO_BROADCAST:                                                       // 配置用于发送广播数据的套接字。此选项仅适用于支持广播 IP 和 UDP 的协议 布尔类型
+            RyanW5500CheckCode(Sn_MR_TCP != sock->type, EINVAL, { return -1; }); // 指定的选项在指定的套接字级别无效或套接字已关闭。
+            RyanW5500CheckCode(sizeof(int) == optlen, EFAULT, { return -1; });
+            if (1 == *(int *)optval)
+                sock->soOptionsFlag |= optname;
+            else
+                sock->soOptionsFlag &= ~optname;
+            break;
+
+        // 暂不实现
+        case SO_KEEPALIVE: // 为套接字连接启用保持连接。 仅适用于支持保持连接的协议,比如tcp, 对于 TCP,默认保持连接超时为 2 小时,保持连接间隔为 1 秒  布尔类型
+            return -1;
+
+        case SO_RCVTIMEO: // 阻止接收调用的超时(以毫秒为单位)。 此选项的默认值为零,表示接收操作不会超时 类型struct timeval
+            RyanW5500CheckCode(sizeof(struct timeval) == optlen, EFAULT, { return -1; });
+            sock->recvTimeout = ((const struct timeval *)optval)->tv_sec * 1000 +
+                                ((const struct timeval *)optval)->tv_usec / 1000;
+            break;
+
+        case SO_SNDTIMEO: // 阻止发送调用的超时(以毫秒为单位)。 此选项的默认值为零,表示发送操作不会超时。类型struct timeval
+            RyanW5500CheckCode(sizeof(struct timeval) == optlen, EFAULT, { return -1; });
+            sock->sendTimeout = ((const struct timeval *)optval)->tv_sec * 1000 +
+                                ((const struct timeval *)optval)->tv_usec / 1000;
+            break;
+
+        // 以下参数没有实现的原因是因为W5500 本身发送 / 接收缓冲区各16K是8个socket共享的
+        // 用户可能不知道他修改的缓冲区是否是正确,如果超过16k则有可能造成个别socket通道发送 / 接收失败
+        case SO_SNDBUF: // 设置发送缓冲区大小。此选项采用 int 值。
+        case SO_RCVBUF: // 设置接收缓冲区大小。此选项采用 int 值。
+
+        case SO_RCVLOWAT: // 此选项设置套接字输入操作要处理的最小字节数
+        case SO_SNDLOWAT: // 此选项设置套接字输出操作要处理的最小字节数
+
+        case SO_DEBUG:     // 启用调试输出
+        case SO_REUSEADDR: // 允许套接字绑定到已使用的地址和端口。布尔类型
+        case SO_LINGER:    // 如果存在数据,则停留在 close()上等待缓存数据发送完毕。 布尔类型
+        case SO_OOBINLINE: // 指示应随常规数据一起返回超出边界的数据。 此选项仅适用于支持带外数据的面向连接的协议。 布尔类型
+        case SO_DONTROUTE: // 指示应在套接字绑定到的任何接口上发送传出数据,而不是在其他接口上路由。 布尔类型
+            return -1;
+
+        default:
+            RyanW5500CheckCode(NULL, ENOPROTOOPT, { return -1; });
+        }
+    }
+    else if (IPPROTO_IP == level)
+    {
+        switch (optname)
+        {
+        case IP_TOS: // 本选项是int型的数值选项,允许对TCP、UDP的IP头中的tos字段进行设置
+            RyanW5500CheckCode(SOCK_OK == wizchip_setsockopt(sock->socket, SO_TOS, optval), EINVAL, { return -1; });
+            break;
+
+        case IP_TTL: // 本选项是int型的数值选项,允许对单播报文的TTL默认值进行设置。
+            RyanW5500CheckCode(SOCK_OK == wizchip_setsockopt(sock->socket, SO_TTL, optval), EINVAL, { return -1; });
+            break;
+
+        // UDP 多播的选项和类型
+        case IP_ADD_MEMBERSHIP: // 加入一个组播组 struct ip_mreq
+        {
+            RyanW5500CheckCode(Sn_MR_TCP != sock->type, EINVAL, { return -1; }); // 指定的选项在指定的套接字级别无效或套接字已关闭。
+            RyanW5500CheckCode(sizeof(struct ip_mreq) == optlen, EFAULT, { return -1; });
+            struct ip_mreq *mreq = (struct ip_mreq *)optval;
+
+            // 需要在Sn_CR命令之前,分开配置组播 IP 地址及端口号。
+            wizchip_close(sock->socket);
+
+            // 组播MAC地址的高24bit为0x01005e,高位第25bit为0,即高25bit为固定值。
+            // MAC地址的低23bit为组播IP地址的低23bit
+            uint8_t ipStrArr[4] = {0};
+            inAddrToipStrArr(&mreq->imr_multiaddr.s_addr, ipStrArr);
+            uint8_t DHAR[6] = {0x01, 0x00, 0x5e};
+            memcpy(DHAR + 3, ipStrArr + 1, 3);
+            DHAR[2] &= ~(1 << 7); // 高位第25bit为0
+            setSn_DHAR(sock->socket, DHAR);
+            setSn_DIPR(sock->socket, ipStrArr);
+            setSn_DPORT(sock->socket, sock->port);
+
+            int8_t result = wizchip_socket(sock->socket, sock->type, sock->port, Sn_MR_MULTI);
+            RyanW5500CheckCode(result == sock->socket, EMFILE, { return -1; });
+            break;
+        }
+
+        case IP_DROP_MEMBERSHIP: // 退出组播组 struct ip_mreq
+        {
+            int8_t result = wizchip_socket(sock->socket, sock->type, sock->port, 0);
+            RyanW5500CheckCode(result == sock->socket, EMFILE, { return -1; });
+            break;
+        }
+
+        case IP_MULTICAST_TTL:  // 设置多播组数据的TTL值, 范围为0~255之间的任何值
+        case IP_MULTICAST_IF:   // 设置用于发送 IPv4 多播流量的传出接口。 struct in_addr
+        case IP_MULTICAST_LOOP: // 对于已加入一个或多个多播组的套接字,此套接字控制它是否将收到通过所选多播接口发送到这些多播组的 传出 数据包的副本。布尔类型
+            return -1;
+            // case IP_RECVDSTADDR:     // 本选项是标志位,置上之后,允许对UDP socket调用recvfrom的时候,能够以辅助数据的形式获取到客户端报文的目的地址。
+            // case IP_RECVIF:          // 本选项是标志位,置上之后,允许对UDP socket调用recvfrom的时候,能够以辅助数据的形式获取到客户端报文的目的接口。
+
+        default:
+            RyanW5500CheckCode(NULL, ENOPROTOOPT, { return -1; });
+        }
+    }
+    else if (IPPROTO_TCP == level)
+    {
+        switch (optname)
+        {
+        case TCP_NODELAY:   // 启用或禁用 TCP 套接字的 Nagle 算法。
+        case TCP_KEEPIDLE:  // 获取或设置 TCP 连接在发送到远程之前保持空闲状态的秒数。
+        case TCP_KEEPINTVL: // 获取或设置 TCP 连接在发送另一个保留探测之前等待保持响应的秒数
+        case TCP_KEEPCNT:   // 获取或设置将在连接终止之前发送的 TCP 保持活动探测数。 将TCP_KEEPCNT设置为大于 255 的值是非法的。
+            return -1;
+        default:
+            RyanW5500CheckCode(NULL, ENOPROTOOPT, { return -1; });
+        }
+    }
+    else
+        RyanW5500CheckCode(NULL, EINVAL, { return -1; });
+
+    return 0;
+}
+
+/**
+ * @brief 获取套接字选项
+ *
+ * @param socket 套接字描述符
+ * @param level 协议栈配置选项
+ * @param optname 需要设置的选项名
+ * @param optval 获取选项值的缓冲区地址
+ * @param optlen 获取选项值的缓冲区长度地址
+ *          如果选项值的大小大于option_len ,存储在option_value参数指向的对象中的值将被静默截断。
+ *          否则, option_len参数指向的对象 应被修改以指示值的实际长度。
+ * @return int
+ */
+int wiz_getsockopt(int socket, int level, int optname, void *optval, socklen_t *optlen)
+{
+    RyanW5500Socket *sock = NULL;
+
+    RyanW5500LinkCheck(-1);
+    RyanW5500CheckCode(NULL != optval && NULL != optlen, EFAULT, { return -1; });
+
+    sock = RyanW5500GetSock(socket);
+    RyanW5500CheckCode(NULL != sock, EBADF, { return -1; });
+
+    if (SOL_SOCKET == level)
+    {
+        switch (optname)
+        {
+        case SO_BROADCAST: // 报告是否支持广播消息的传输 布尔类型
+            RyanW5500CheckCode(sizeof(int) <= *optlen, EINVAL, { return -1; });
+            *(int *)optval = Sn_MR_TCP != sock->type ? 1 : 0;
+            *optlen = sizeof(int);
+            break;
+
+            // 暂不实现
+        case SO_KEEPALIVE: // 报告连接是否通过定期传输消息保持活动状态  布尔类型
+            return -1;
+
+        case SO_RCVTIMEO: // 报告阻止接收调用的超时。 类型struct timeval
+            RyanW5500CheckCode(sizeof(struct timeval) <= *optlen, EINVAL, { return -1; });
+            ((struct timeval *)(optval))->tv_sec = sock->recvTimeout / 1000U;
+            ((struct timeval *)(optval))->tv_usec = (sock->recvTimeout % 1000U) * 1000U;
+            *optlen = sizeof(struct timeval);
+            break;
+
+        case SO_SNDTIMEO: // 报告阻止发送调用的超时。 此选项的默认值为零,表示发送操作不会超时。类型struct timeval
+            RyanW5500CheckCode(sizeof(struct timeval) <= *optlen, EINVAL, { return -1; });
+            ((struct timeval *)optval)->tv_sec = sock->sendTimeout / 1000U;
+            ((struct timeval *)optval)->tv_usec = (sock->sendTimeout % 1000U) * 1000U;
+            *optlen = sizeof(struct timeval);
+            break;
+
+        case SO_SNDBUF: // 报告发送缓冲区大小。此选项采用 int 值。
+            RyanW5500CheckCode(sizeof(int) <= *optlen, EINVAL, { return -1; });
+            wizchip_getsockopt(socket, (sockopt_type)SO_SENDBUF, (void *)optval);
+            *optlen = sizeof(int);
+            break;
+
+        case SO_RCVBUF: // 报告接收缓冲区大小。此选项采用 int 值。
+            RyanW5500CheckCode(sizeof(int) <= *optlen, EINVAL, { return -1; });
+            wizchip_getsockopt(socket, (sockopt_type)SO_RECVBUF, (void *)optval);
+            *optlen = sizeof(int);
+            break;
+
+        case SO_ACCEPTCONN: // 报告是否启用套接字侦听 布尔类型
+            RyanW5500CheckCode(sizeof(int) <= *optlen, EINVAL, { return -1; });
+            if (RyanW5500SocketListen == sock->state && NULL != sock->serviceInfo)
+                *(int *)optval = 1;
+            else
+                *(int *)optval = 0;
+            *optlen = sizeof(int);
+            break;
+
+        case SO_ERROR: // 报告有关错误状态的信息并将其清除。 int
+            RyanW5500CheckCode(sizeof(int) <= *optlen, EINVAL, { return -1; });
+            *(int *)optval = errno;
+            *optlen = sizeof(int);
+            errno = 0;
+            break;
+
+        case SO_TYPE: // 报告套接字类型   int
+            RyanW5500CheckCode(sizeof(int) <= *optlen, EINVAL, { return -1; });
+            *(int *)optval = sock->type;
+            *optlen = sizeof(int);
+            break;
+
+        case SO_DEBUG:     // 报告是否正在记录调试信息 布尔类型
+        case SO_REUSEADDR: // 报告是否允许套接字绑定到已使用的地址和端口。布尔类型
+        case SO_LINGER:    // 报告套接字是否停留在 close()上
+        case SO_OOBINLINE: // 报告套接字是否保留接收到的带外数据  此选项仅适用于支持带外数据的面向连接的协议。 布尔类型
+        case SO_DONTROUTE: // 报告是否允许指示应在套接字绑定到的任何接口上发送传出数据,而不是在其他接口上路由。 布尔类型
+        case SO_RCVLOWAT:  // 报告套接字输入操作要处理的最小字节数 int
+        case SO_SNDLOWAT:  // 报告套接字输出操作要处理的最小字节数 int
+            return -1;
+
+        default:
+            RyanW5500CheckCode(NULL, ENOPROTOOPT, { return -1; });
+        }
+    }
+    else if (IPPROTO_IP == level)
+    {
+        switch (optname)
+        {
+        case IP_TOS: // 本选项是int型的数值选项,允许对TCP、UDP的IP头中的tos字段进行获取
+            RyanW5500CheckCode(sizeof(int) <= *optlen, EINVAL, { return -1; });
+            wizchip_getsockopt(sock->socket, (sockopt_type)SO_TOS, optval);
+            *optlen = sizeof(int);
+            break;
+
+        case IP_TTL: // 本选项是int型的数值选项,允许对单播报文的TTL默认值进行获取
+            RyanW5500CheckCode(sizeof(int) <= *optlen, EINVAL, { return -1; });
+            wizchip_getsockopt(sock->socket, (sockopt_type)SO_TTL, optval);
+            *optlen = sizeof(int);
+            break;
+
+        // UDP 多播的选项和类型
+        case IP_MULTICAST_TTL: // 获取多播组数据的TTL值, 范围为0~255之间的任何值
+        case IP_MULTICAST_IF:  // 获取用于发送 IPv4 多播流量的传出接口。 struct in_addr
+            return -1;
+
+            // case IP_RECVDSTADDR: // 本选项是标志位,置上之后,允许对UDP socket调用recvfrom的时候,能够以辅助数据的形式获取到客户端报文的目的地址。
+            // case IP_RECVIF:      // 本选项是标志位,置上之后,允许对UDP socket调用recvfrom的时候,能够以辅助数据的形式获取到客户端报文的目的接口。
+            //     return -1;
+
+        default:
+            RyanW5500CheckCode(NULL, ENOPROTOOPT, { return -1; });
+        }
+    }
+    else if (IPPROTO_TCP == level)
+    {
+        switch (optname)
+        {
+        case TCP_NODELAY:   // 获取或设置 TCP 套接字的 Nagle 算法。
+        case TCP_KEEPIDLE:  // 获取或设置 TCP 连接在发送到远程之前保持空闲状态的秒数。
+        case TCP_KEEPINTVL: // 获取或设置 TCP 连接在发送另一个保留探测之前等待保持响应的秒数
+        case TCP_KEEPCNT:   // 获取或设置将在连接终止之前发送的 TCP 保持活动探测数。 将TCP_KEEPCNT设置为大于 255 的值是非法的。
+            return -1;
+        default:
+            RyanW5500CheckCode(NULL, ENOPROTOOPT, { return -1; });
+        }
+    }
+    else
+        RyanW5500CheckCode(NULL, EINVAL, { return -1; });
+
+    return 0;
+
+    return 0;
+}
+
+int RyanW5500_gethostbyname(const char *name, ip_addr_t *addr)
+{
+    int idx = 0;
+    int nameLen = strlen(name);
+    char ipStrArr[16] = {0};
+
+    // 检查域名 / ip地址
+    for (idx = 0; idx < nameLen && !isalpha(name[idx]); idx++)
+        ;
+
+    // 输入名称为ip地址
+    if (idx == strlen(name))
+        strncpy(ipStrArr, name, nameLen);
+    // 输入名称为域名需要调用dns
+    else
+    {
+        int8_t ret = 0;
+        uint8_t remote_ip[4] = {0};
+        uint8_t data_buffer[512];
+
+        // DNS客户端处理
+        ret = DNS_run(gWIZNETINFO.dns, (uint8_t *)name, remote_ip, data_buffer);
+        if (1 != ret)
+        {
+            if (-1 == ret)
+            {
+                LOG_E("MAX_DOMAIN_NAME is too small, should be redefined it.");
+                return -1;
+            }
+
+            if (-2 == ret)
+            {
+                LOG_E("DNS failed, socket number is full.");
+                return -2;
+            }
+            return -1;
+        }
+
+        // 域解析失败
+        if (remote_ip[0] == 0)
+            return -1;
+
+        snprintf(ipStrArr, 16, "%u.%u.%u.%u", remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3]);
+    }
+
+    inet_aton(ipStrArr, addr);
+    return 0;
+}
+
+/**
+ * @brief 根据主机名解析地址信息 DNS
+ *
+ * @param name 主机名,dns规定长度限制为255
+ * @return struct hostent*
+ */
+struct hostent *wiz_gethostbyname(const char *name)
+{
+    // 检查WIZnet初始化状态
+    RyanW5500LinkCheck(NULL);
+
+    ip_addr_t addr;
+    int err = 0;
+
+    // 用于 gethostbyname() 的缓冲区变量
+    static struct hostent s_hostent;
+    static char s_hostname[DNS_MAX_NAME_LENGTH + 1]; // 主机名称
+    static char *s_aliases;                          // 主机别名
+    static ip_addr_t s_hostent_addr;                 // 临时主机IP
+    static ip_addr_t *s_phostent_addr[2];            // 主机IP
+
+    if (NULL == name)
+    {
+        LOG_E("gethostbyname input name err!");
+        return NULL;
+    }
+
+    if (strlen(name) > DNS_MAX_NAME_LENGTH)
+        return NULL;
+
+    err = RyanW5500_gethostbyname(name, &addr);
+    if (0 != err)
+    {
+        // 不支持h_errno
+        // RyanW5500CheckCode(-1 == result, HOST_NOT_FOUND, return NULL);
+        // RyanW5500CheckCode(-2 == result, TRY_AGAIN, return NULL);
+        return NULL;
+    }
+
+    // 填充主机结构
+    s_hostent_addr = addr;
+    s_phostent_addr[0] = &s_hostent_addr;
+    s_phostent_addr[1] = NULL;
+    strncpy(s_hostname, name, DNS_MAX_NAME_LENGTH);
+    s_hostname[DNS_MAX_NAME_LENGTH] = 0;
+    s_aliases = NULL;
+
+    s_hostent.h_name = s_hostname;
+    s_hostent.h_aliases = &s_aliases;
+    s_hostent.h_addrtype = AF_INET;
+    s_hostent.h_length = sizeof(ip_addr_t);
+    s_hostent.h_addr_list = (char **)&s_phostent_addr;
+
+    return &s_hostent;
+}
+
+// 看以后要不要实现了
+
+/**
+ * @brief wiz_gethostbyname 线程安全版本
+ *
+ * @param name 主机名,dns规定长度限制为255
+ * @param ret 预先分配的结构体,用于存储结果
+ * @param buf 预先分配的缓冲区,用于存储额外的数据
+ * @param buflen 缓冲区大小
+ * @param result 指向主机指针的指针,成功时设置为 ret,错误时设置为零
+ * @param h_errnop 指向存储错误的 int 的指针(而不是修改全局 h_errno)
+ * @return int 0成功,非0错误
+ */
+int wiz_gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop)
+{
+
+    // 检查WIZnet初始化状态
+    RyanW5500LinkCheck(NULL);
+
+    // gethostbyname_r 的辅助结构,用于访问hostent中的 char*缓冲区
+    struct gethostbyname_r_helper
+    {
+        ip_addr_t *addr_list[2];
+        ip_addr_t addr;
+        char *aliases;
+    };
+
+    int err;
+    struct gethostbyname_r_helper *h;
+    char *hostname;
+    size_t namelen;
+    int lh_errno;
+
+    if (h_errnop == NULL)
+        h_errnop = &lh_errno; // 确保 h_errnop 永远不会为 NULL
+
+    if ((name == NULL) || (ret == NULL) || (buf == NULL))
+    {
+        *h_errnop = EINVAL; // 参数不足
+        return -1;
+    }
+
+    if (result == NULL)
+    {
+        *h_errnop = EINVAL; // 参数不足
+        return -1;
+    }
+
+    // 第一件事:将 *result 设置为空
+    *result = NULL;
+
+    namelen = strlen(name);
+    if (buflen < (sizeof(struct gethostbyname_r_helper) + (namelen + 1))) // 计算buf是否足够存储hostent信息
+    {
+        *h_errnop = ERANGE; // buf 不能保存所需的数据 + 名称的副本
+        return -1;
+    }
+
+    h = (struct gethostbyname_r_helper *)buf;                       // 从buf中分配用于hostent中的 char*缓冲区
+    hostname = ((char *)h) + sizeof(struct gethostbyname_r_helper); // 从buf中分配用于hostent中 h_name缓冲区
+
+    err = RyanW5500_gethostbyname(name, &h->addr);
+    if (0 != err)
+    {
+        *h_errnop = HOST_NOT_FOUND;
+        return -1;
+    }
+
+    // 拷贝hostname信息
+    memcpy(hostname, name, namelen);
+    hostname[namelen] = 0;
+
+    // 填充主机结构
+    h->addr_list[0] = &h->addr;
+    h->addr_list[1] = NULL;
+    h->aliases = NULL;
+
+    ret->h_name = hostname;
+    ret->h_aliases = &h->aliases;
+    ret->h_addrtype = AF_INET;
+    ret->h_length = sizeof(ip_addr_t);
+    ret->h_addr_list = (char **)&h->addr_list;
+
+    // 设置结果
+    *result = ret;
+
+    return 0;
+}
+
+/**
+ * @brief 获取地址信息,应该是线程安全的
+ * !没有ipv6实现,只支持ipv4 地址
+ *
+ * @param nodename 主机名,可以是域名,也可以是地址的点分十进制字符串
+ * @param servname 服务名可以是十进制的端口号("8080")字符串,(也可以是已定义的服务名称,如"ftp"、"http"等,当前接口不支持)
+ * @param hints 用户设定的 struct addrinfo 结构体
+ * @param result 该参数获取一个指向存储结果的 struct addrinfo 结构体列表,使用完成后调用 freeaddrinfo() 释放存储结果空间。
+ * @return int
+ */
+int wiz_getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **result)
+{
+
+    // 检查WIZnet初始化状态
+    RyanW5500LinkCheck(NULL);
+
+    int err = 0;
+    int port_nr = 0;
+    ip_addr_t addr;
+    struct addrinfo *ai = NULL;
+    struct sockaddr_storage *sa = NULL;
+    size_t total_size = 0;
+    size_t namelen = 0;
+    int ai_family = 0;
+
+    if (NULL == result)
+        return EAI_FAIL;
+
+    *result = NULL;
+
+    // nodename 和 servname 可以设置为NULL,但同时只能有一个为NUL。
+    if ((NULL == nodename) && (NULL == servname))
+        return EAI_NONAME;
+
+    if (NULL == hints)
+        ai_family = AF_UNSPEC;
+    else
+    {
+        ai_family = hints->ai_family; // 套接字的地址族
+
+        if (ai_family != AF_WIZ &&
+            ai_family != AF_INET &&
+            ai_family != AF_UNSPEC)
+            return EAI_FAMILY;
+    }
+
+    // 指定的服务名称: 转换为端口号
+    if (servname != NULL)
+    {
+        port_nr = atoi(servname);
+        if ((port_nr <= 0) || (port_nr > 0xffff))
+            return EAI_SERVICE;
+    }
+
+    if (NULL == nodename)
+    {
+        inet_aton("127.0.0.1", &addr); // 没有指定服务位置,请使用回送地址
+    }
+    else if (nodename != NULL)
+    {
+        // 指定了服务位置,尝试解析
+        if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST))
+        {
+            if (AF_INET != ai_family)
+                return EAI_NONAME;
+
+            // 解析地址字符串
+            if (!inet_aton(nodename, (ip4_addr_t *)&addr))
+                return EAI_NONAME;
+        }
+        else
+        {
+            err = RyanW5500_gethostbyname(nodename, &addr);
+            if (0 != err)
+                return EAI_FAIL;
+        }
+    }
+
+    total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage);
+    if (NULL != nodename)
+    {
+        namelen = strlen(nodename);
+        if (namelen > DNS_MAX_NAME_LENGTH)
+            return EAI_FAIL;
+
+        total_size += namelen + 1;
+    }
+
+    if (total_size > sizeof(struct addrinfo) + sizeof(struct sockaddr_storage) + DNS_MAX_NAME_LENGTH + 1)
+        return EAI_FAIL;
+
+    ai = (struct addrinfo *)malloc(total_size);
+    if (ai == NULL)
+        return ENOMEM;
+
+    memset(ai, 0, total_size);
+
+    // 通过void强制转换 * 以消除对齐警告
+    sa = (struct sockaddr_storage *)(void *)((uint8_t *)ai + sizeof(struct addrinfo));
+    struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
+
+    /* set up sockaddr */
+    sa4->sin_addr.s_addr = addr.addr;
+    sa4->sin_family = AF_INET;
+    sa4->sin_len = sizeof(struct sockaddr_in);
+    sa4->sin_port = htons((uint16_t)port_nr);
+    ai->ai_family = AF_INET;
+
+    // 设置addrinfo
+    if (hints != NULL)
+    {
+        // 如果指定,从指定中复制套接字类型和协议
+        ai->ai_socktype = hints->ai_socktype;
+        ai->ai_protocol = hints->ai_protocol;
+    }
+
+    if (nodename != NULL)
+    {
+        // 如果指定,将节点名称复制到canonname
+        ai->ai_canonname = ((char *)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage));
+        memcpy(ai->ai_canonname, nodename, namelen);
+        ai->ai_canonname[namelen] = 0;
+    }
+
+    ai->ai_addrlen = sizeof(struct sockaddr_storage);
+    ai->ai_addr = (struct sockaddr *)sa;
+
+    *result = ai;
+    return 0;
+}
+
+void wiz_freeaddrinfo(struct addrinfo *ai)
+{
+    struct addrinfo *next = NULL;
+
+    while (ai != NULL)
+    {
+        next = ai->ai_next;
+        free(ai);
+        ai = next;
+    }
+}

+ 80 - 0
W5500Client/RyanW5500Socket.h

@@ -0,0 +1,80 @@
+
+
+#ifndef __RyanW5500Socket__
+#define __RyanW5500Socket__
+
+#include "RyanW5500Store.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+    // 定义枚举类型
+    typedef enum
+    {
+        RyanW5500SocketInit,        // 初始化状态
+        RyanW5500SocketEstablished, // 以连接状态,调用connect后
+        RyanW5500SocketListen,      // 监听状态
+        RyanW5500SocketClose,       // 关闭状态
+    } RyanW5500SocketState_e;
+
+    typedef struct
+    {
+        int backlog;                   // 剩余accept连接个数
+        rt_mq_t clientInfoQueueHandle; // 连接的客户端信息地址
+        RyanList_t clientList;    // 客户端的列表
+    } RyanW5500ServiceInfo;
+
+    typedef struct
+    {
+        uint8_t type;                      // WIZnet 套接字的类型(TCP、UDP 或 RAW)
+        uint8_t soOptionsFlag;             // so_options标志位
+        int8_t serviceSocket;              // 当前套接字是listen套接字客户端时,存储listen服务套接字
+        uint16_t port;                     // 当前socket端口
+        int socket;                        // w5500 真实socket套接字
+        uint32_t magic;                    // 
+        uint32_t recvTimeout;              // 接收数据超时(以毫秒为单位)
+        uint32_t sendTimeout;              // 等待发送超时(以毫秒为单位)
+        RyanW5500SocketState_e state;      // RyanW5500 套接字的当前状态
+        struct sockaddr *remoteAddr;       // 远程地址
+        RyanW5500ServiceInfo *serviceInfo; // 服务器套接字信息
+
+    } RyanW5500Socket;
+
+    typedef struct
+    {
+        RyanW5500Socket *sock;
+        RyanList_t list;
+    } RyanW5500ClientInfo;
+
+    /* extern variables-----------------------------------------------------------*/
+    extern int wiz_socket(int domain, int type, int protocol);
+    extern int wiz_closesocket(int socket);
+    extern int wiz_shutdown(int socket, int how);
+    extern int wiz_listen(int socket, int backlog);
+    extern int wiz_bind(int socket, const struct sockaddr *name, socklen_t namelen);
+    extern int wiz_connect(int socket, const struct sockaddr *name, socklen_t namelen);
+    extern int wiz_accept(int socket, struct sockaddr *addr, socklen_t *addrlen);
+    extern int wiz_sendto(int socket, const void *dwiza, size_t size, int flags, const struct sockaddr *to, socklen_t tolen);
+    extern int wiz_send(int socket, const void *dwiza, size_t size, int flags);
+    extern int wiz_recvfrom(int socket, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
+    extern int wiz_recv(int socket, void *mem, size_t len, int flags);
+    extern int wiz_getsockopt(int socket, int level, int optname, void *optval, socklen_t *optlen);
+    extern int wiz_setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen);
+
+    extern struct hostent *wiz_gethostbyname(const char *name);
+    extern int wiz_gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop);
+    extern int wiz_getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
+    extern void wiz_freeaddrinfo(struct addrinfo *ai);
+
+
+    extern RyanW5500Socket *RyanW5500GetSock(int socket); // 获取 WIZnet 套接字对象
+    extern int RyanW5500RecvDataCallback(int socket);
+    extern int RyanW5500CloseCallback(int socket);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 10 - 0
W5500Client/RyanW5500Store.c

@@ -0,0 +1,10 @@
+#include "RyanW5500Store.h"
+
+wiz_NetInfo gWIZNETINFO = {.mac = {0x00, 0x08, 0xdc, 0x00, 0xab, 0xcd},
+                           .ip = {192, 168, 3, 20},
+                           .sn = {255, 255, 252, 0},
+                           .gw = {192, 168, 1, 1},
+                           .dns = {114, 114, 114, 114},
+                           .dhcp = NETINFO_DHCP};
+
+RyanW5500Entry_t RyanW5500Entry = {0};

+ 98 - 0
W5500Client/RyanW5500Store.h

@@ -0,0 +1,98 @@
+
+#ifndef __RyanW5500Store__
+#define __RyanW5500Store__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME ("RyanW5500")
+#define DBG_LEVEL LOG_LVL_WARNING
+#define DBG_COLOR
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include "ulog.h"
+#include "sal.h"
+#include "platformTimer.h"
+#include "platformW5500Hardware.h"
+#include "wizchip_conf.h"
+#include "wizchip_socket.h"
+#include "wizchip_dhcp.h"
+#include "wizchip_dns.h"
+#include "w5500.h"
+#include "RyanList.h"
+#include "RyanW5500.h"
+#include "RyanW5500Socket.h"
+
+#ifndef delay
+#define delay(ms) rt_thread_mdelay(ms)
+#endif
+
+#define RyanW5500SetErrno(err) \
+    do                         \
+    {                          \
+        if (err)               \
+            errno = (err);     \
+    } while (0)
+
+#define RyanW5500Check(EX, ErrorCode) RyanW5500CheckCode(EX, ErrorCode, NULL)
+
+#define RyanW5500CheckCode(EX, ErrorCode, code)                    \
+    if (!(EX))                                                     \
+    {                                                              \
+        LOG_D("%s:%d ErrorCode: %d, strError: %s",                 \
+              __FILE__, __LINE__, ErrorCode, strerror(ErrorCode)); \
+        RyanW5500SetErrno(ErrorCode);                              \
+        {                                                          \
+            code                                                   \
+        }                                                          \
+    }
+
+// WIZnet套接字魔术词
+#define WIZ_SOCKET_MAGIC 0x3120
+
+// WIZnet 套接字地址系列
+#ifndef AF_WIZ
+#define AF_WIZ 46
+#endif
+
+#define RyanW5500MaxSocketNum (_WIZCHIP_SOCK_NUM_)
+#define netDevDHCP (1 << 2)
+#define netDevSetDevInfo (1 << 3)
+
+// event标志
+// 前8bit用于socket通道数据解析
+#define RyanW5500IRQBit (1 << RyanW5500MaxSocketNum)
+
+#define RyanW5500SnIMR (Sn_IR_RECV | Sn_IR_DISCON | Sn_IR_CON)     // Sn_IMR
+#define RyanW5500IMR (IR_CONFLICT | IR_UNREACH | IR_PPPoE | IR_MP) // IMR (中断屏蔽寄存器)
+
+    // 定义枚举类型
+
+    // 定义结构体类型
+    typedef struct
+    {
+        char *netdevName; // netDev名称
+        uint32_t netDevFlag;
+        rt_timer_t W5500TimerHandle;
+        rt_event_t W5500EventHandle;    // 事件标志组,用于中断通知和socket状态通知
+        rt_mutex_t socketMutexHandle;   // socket锁
+        rt_mutex_t W5500SpiMutexHandle; // spi锁
+        rt_thread_t w5500TaskHandle;    // W5500线程
+    } RyanW5500Entry_t;
+
+    /* extern variables-----------------------------------------------------------*/
+
+    extern wiz_NetInfo gWIZNETINFO;
+    extern RyanW5500Entry_t RyanW5500Entry;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 215 - 0
W5500Client/RyanW5500netDev.c

@@ -0,0 +1,215 @@
+
+#include "RyanW5500Store.h"
+
+/**
+ * @brief link up
+ *
+ * @param netdev
+ * @return int
+ */
+static int RyanW5500NetdevSetUp(struct netdev *netdev)
+{
+    netdev_low_level_set_status(netdev, RT_TRUE);
+    return RT_EOK;
+}
+
+/**
+ * @brief link down
+ *
+ * @param netdev
+ * @return int
+ */
+static int RyanW5500NetdevSetDown(struct netdev *netdev)
+{
+    netdev_low_level_set_status(netdev, RT_FALSE);
+    return RT_EOK;
+}
+
+/**
+ * @brief set addr info
+ *
+ * @param netdev
+ * @param ip_addr
+ * @param netmask
+ * @param gw
+ * @return int
+ */
+static int RyanW5500NetdevSetAddrInfo(struct netdev *netdev, ip_addr_t *ip_addr, ip_addr_t *netmask, ip_addr_t *gw)
+{
+    RT_ASSERT(netdev);
+    RT_ASSERT(ip_addr || netmask || gw);
+
+    if (ip_addr)
+        memcpy(gWIZNETINFO.ip, &ip_addr->addr, sizeof(gWIZNETINFO.ip));
+
+    if (netmask)
+        memcpy(gWIZNETINFO.sn, &netmask->addr, sizeof(gWIZNETINFO.sn));
+
+    if (gw)
+        memcpy(gWIZNETINFO.gw, &gw->addr, sizeof(gWIZNETINFO.gw));
+
+    RyanW5500Entry.netDevFlag |= netDevSetDevInfo;
+    netdev_low_level_set_link_status(netdev, RT_FALSE);
+    return RT_EOK;
+}
+
+/**
+ * @brief set dns server
+ *
+ * @param netdev
+ * @param dns_num
+ * @param dns_server
+ * @return int
+ */
+static int RyanW5500NetdevSetDnsServer(struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server)
+{
+    RT_ASSERT(netdev);
+    RT_ASSERT(dns_server);
+    if (0 != dns_num)
+        return -RT_ERROR;
+
+    RyanW5500Entry.netDevFlag |= netDevSetDevInfo;
+    memcpy(gWIZNETINFO.dns, &dns_server->addr, sizeof(gWIZNETINFO.dns));
+    netdev_low_level_set_link_status(netdev, RT_FALSE);
+    return RT_EOK;
+}
+
+/**
+ * @brief set dhcp
+ *
+ * @param netdev
+ * @param is_enabled
+ * @return int
+ */
+static int RyanW5500NetdevSetDhcp(struct netdev *netdev, rt_bool_t is_enabled)
+{
+
+    RyanW5500Entry.netDevFlag |= netDevDHCP;
+
+    netdev_low_level_set_dhcp_status(netdev, is_enabled);
+    netdev_low_level_set_link_status(netdev, RT_FALSE);
+    return RT_EOK;
+}
+
+/**
+ * @brief ping
+ *
+ * @param netdev
+ * @param host
+ * @param data_len
+ * @param timeout
+ * @param ping_resp
+ * @return int
+ */
+static int RyanW5500NetdevPing(struct netdev *netdev, const char *host, size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp)
+{
+    RT_ASSERT(netdev);
+    RT_ASSERT(host);
+    RT_ASSERT(ping_resp);
+
+    return RyanW5500Ping(netdev, host, data_len, timeout, ping_resp);
+}
+
+/**
+ * @brief 用于网卡网络连接信息和端口使用情况
+ *
+ * @param netdev
+ * @return int
+ */
+static int RyanW5500NetdevNetstat(struct netdev *netdev)
+{
+    return 0;
+}
+
+// netdev设备操作
+const struct netdev_ops wiz_netdev_ops =
+    {
+        .set_up = RyanW5500NetdevSetUp,
+        .set_down = RyanW5500NetdevSetDown,
+        .set_addr_info = RyanW5500NetdevSetAddrInfo,
+        .set_dns_server = RyanW5500NetdevSetDnsServer,
+        .set_dhcp = RyanW5500NetdevSetDhcp,
+#ifdef RT_USING_FINSH
+        .ping = RyanW5500NetdevPing,
+        .netstat = RyanW5500NetdevNetstat,
+#endif
+};
+
+/**
+ * @brief socket操作
+ *
+ */
+static struct sal_socket_ops RyanW5500SocketOps =
+    {
+        .socket = wiz_socket,
+        .closesocket = wiz_closesocket,
+        .bind = wiz_bind,
+        .listen = wiz_listen,
+        .connect = wiz_connect,
+        .accept = wiz_accept,
+        .sendto = wiz_sendto,
+        .recvfrom = wiz_recvfrom,
+        .getsockopt = wiz_getsockopt,
+        .setsockopt = wiz_setsockopt,
+        .shutdown = wiz_shutdown,
+        .getpeername = NULL,
+        .getsockname = NULL,
+        .ioctlsocket = NULL,
+        // #ifdef SAL_USING_POSIX
+        //         wiz_poll,
+        // #endif /* SAL_USING_POSIX */
+};
+
+/**
+ * @brief sal 网络数据库名称解析
+ *
+ */
+static const struct sal_netdb_ops RyanW5500NetdbOps =
+    {
+        .gethostbyname = wiz_gethostbyname,
+        .gethostbyname_r = wiz_gethostbyname_r,
+        .getaddrinfo = wiz_getaddrinfo,
+        .freeaddrinfo = wiz_freeaddrinfo,
+};
+
+/**
+ * @brief RyanW5500支持的协议族
+ *
+ */
+static const struct sal_proto_family RyanW5500Family =
+    {
+        .family = AF_WIZ,
+        .sec_family = AF_INET,
+        .skt_ops = &RyanW5500SocketOps,
+        .netdb_ops = &RyanW5500NetdbOps,
+};
+
+/**
+ * @brief RyanW5500注册到netdev
+ *
+ * @param netdev_name
+ * @return struct netdev*
+ */
+struct netdev *RyanW5500NetdevRegister(const char *netdev_name)
+{
+    struct netdev *netdev = NULL;
+
+    netdev = (struct netdev *)malloc(sizeof(struct netdev));
+    if (NULL == netdev)
+        return NULL;
+    memset(netdev, 0, sizeof(struct netdev));
+
+    netdev->flags = 0;                                // 网络接口设备状态标志
+    netdev->mtu = 1460;                               // 最大传输单位 (以字节为单位)
+    netdev->hwaddr_len = 6;                           // 硬件地址长度 mac地址
+    netdev->ops = &wiz_netdev_ops;                    // 网卡操作回调函数
+    netdev->sal_user_data = (void *)&RyanW5500Family; // sal协议族相关参数
+
+    if (0 != netdev_register(netdev, netdev_name, NULL))
+    {
+        free(netdev);
+        return NULL;
+    }
+
+    return netdev;
+}

+ 30 - 0
W5500Client/RyanW5500netDev.h

@@ -0,0 +1,30 @@
+
+
+#ifndef __RyanW5500netDev__
+#define __RyanW5500netDev__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rthw.h>
+#include <stdint.h>
+
+#include <netdb.h>
+#include <sys/socket.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+    // 定义枚举类型
+
+    // 定义结构体类型
+
+    /* extern variables-----------------------------------------------------------*/
+    extern struct netdev *RyanW5500NetdevRegister(const char *netdev_name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 132 - 0
common/RyanList.c

@@ -0,0 +1,132 @@
+
+
+#include "RyanList.h"
+
+// 此库为公共库,别的包也有使用
+#define __weak __attribute__((weak)) // 防止函数重定义, gcc / ARM编译器有效  IAR可以注释此行
+
+/**
+ * @brief 在prev和next之前插入节点
+ *
+ * @param node
+ * @param prev
+ * @param next
+ */
+static void _RyanListAdd(RyanList_t *node, RyanList_t *prev, RyanList_t *next)
+{
+    next->prev = node;
+    node->next = next;
+    node->prev = prev;
+    prev->next = node;
+}
+
+/**
+ * @brief 删除prev和next之间的节点
+ *
+ * @param prev
+ * @param next
+ */
+static void _RyanListDel(RyanList_t *prev, RyanList_t *next)
+{
+    prev->next = next;
+    next->prev = prev;
+}
+
+/**
+ * @brief 删除自己
+ *
+ * @param entry
+ */
+static void _RyanListDel_entry(RyanList_t *entry)
+{
+    _RyanListDel(entry->prev, entry->next);
+}
+
+/**
+ * @brief 初始链表
+ *
+ * @param list
+ */
+__weak void RyanListInit(RyanList_t *list)
+{
+    list->next = list;
+    list->prev = list;
+}
+
+/**
+ * @brief 链表头插
+ *
+ * @param node
+ * @param list
+ */
+__weak void RyanListAdd(RyanList_t *node, RyanList_t *list)
+{
+    _RyanListAdd(node, list, list->next);
+}
+
+/**
+ * @brief 链表尾插
+ *
+ * @param node
+ * @param list
+ */
+__weak void RyanListAddTail(RyanList_t *node, RyanList_t *list)
+{
+    _RyanListAdd(node, list->prev, list);
+}
+
+/**
+ * @brief 删除自己
+ *
+ * @param entry
+ */
+__weak void RyanListDel(RyanList_t *entry)
+{
+    _RyanListDel_entry(entry);
+}
+
+/**
+ * @brief 删除自己
+ *
+ * @param entry
+ */
+__weak void RyanListDelInit(RyanList_t *entry)
+{
+    _RyanListDel_entry(entry);
+    RyanListInit(entry);
+}
+
+/**
+ * @brief 将节点移到链表头部
+ *
+ * @param node
+ * @param list
+ */
+__weak void RyanListMove(RyanList_t *node, RyanList_t *list)
+{
+    _RyanListDel_entry(node);
+    RyanListAdd(node, list);
+}
+
+/**
+ * @brief 将节点移到链表尾部
+ *
+ * @param node
+ * @param list
+ */
+__weak void RyanListMoveTail(RyanList_t *node, RyanList_t *list)
+{
+    _RyanListDel_entry(node);
+    RyanListAddTail(node, list);
+}
+
+/**
+ * @brief 链表是否为空
+ *
+ * @param list
+ * @return int
+ */
+__weak int RyanListIsEmpty(RyanList_t *list)
+{
+    return list->next == list;
+}

+ 75 - 0
common/RyanList.h

@@ -0,0 +1,75 @@
+
+#ifndef __RyanList__
+#define __RyanList__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define RyanOffsetOf(type, member) ((size_t) & (((type *)0)->member))
+
+#define RyanContainerOf(ptr, type, member) \
+    ((type *)((unsigned char *)(ptr)-RyanOffsetOf(type, member)))
+
+// 通过链表获取节点首地址
+#define RyanListEntry(list, type, member) \
+    RyanContainerOf(list, type, member)
+
+// 从链表指针ptr的下一指针中获得包含该链表的结构体指针
+#define RyanListFirstEntry(list, type, member) \
+    RyanListEntry((list)->next, type, member)
+
+// 从链表指针ptr的上一指针中获得包含该链表的结构体指针
+#define RyanListPrevEntry(list, type, member) \
+    RyanListEntry((list)->prev, type, member)
+
+// 遍历链表正序
+#define RyanListForEach(curr, list) \
+    for ((curr) = (list)->next; (curr) != (list); (curr) = (curr)->next)
+
+// 遍历链表反序
+#define RyanListForEachPrev(curr, list) \
+    for ((curr) = (list)->prev; (curr) != (list); (curr) = (curr)->prev)
+
+// 安全遍历链表正序
+#define RyanListForEachSafe(curr, next, list)          \
+    for ((curr) = (list)->next, (next) = (curr)->next; \
+         (curr) != (list);                             \
+         (curr) = (next), (next) = (curr)->next)
+
+// 安全遍历链表反序
+#define RyanListForEachPrevSafe(curr, next, list)      \
+    for ((curr) = (list)->prev, (next) = (curr)->prev; \
+         (curr) != (list);                             \
+         (curr) = (next), (next) = (curr)->prev)
+
+    // 定义枚举类型
+
+    // 定义结构体类型
+    typedef struct RyanListNode
+    {
+        struct RyanListNode *next;
+        struct RyanListNode *prev;
+    } RyanList_t;
+
+    /* extern variables-----------------------------------------------------------*/
+
+    extern void RyanListInit(RyanList_t *list);
+
+    extern void RyanListAdd(RyanList_t *node, RyanList_t *list);
+    extern void RyanListAddTail(RyanList_t *node, RyanList_t *list);
+
+    extern void RyanListDel(RyanList_t *entry);
+    extern void RyanListDelInit(RyanList_t *entry);
+
+    extern void RyanListMove(RyanList_t *node, RyanList_t *list);
+    extern void RyanListMoveTail(RyanList_t *node, RyanList_t *list);
+
+    extern int RyanListIsEmpty(RyanList_t *list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 774 - 0
example/RyanW5500Test.c

@@ -0,0 +1,774 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <board.h>
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rtdbg.h>
+#include "ulog.h"
+#include "RyanW5500.h"
+#include "sal_socket.h"
+#include "sal_netdb.h"
+#include "netdev_ipaddr.h"
+#include "netdev.h"
+
+static const char *TAG = "RyanW5500Test";
+
+// 任务句柄
+struct netdev *ryanNetDev = NULL;
+
+void neDevStatusChangeCallback(struct netdev *netdev, enum netdev_cb_type type)
+{
+    ulog_i(TAG, "w5500 nedev state: %d", type);
+}
+
+int w5500Start(void)
+{
+
+    wiz_NetInfo netInfo = {0};
+
+    // mac地址有48位,6字节
+    // mac地址前3字节表示网卡制造商,由IEEE分配,称为OUI(组织唯一标识符), 后3字节,为网卡制造商分配的唯一编号
+    // mac地址首位偶数单播,首位奇数为多播地址,多播作为设备地址是无效(第一个字节的最后一位0 单播, 1 多播)
+    // 广播mac地址:FF-FF-FF-FF-FF-FF
+    // 第一个字节一般为00,这里就不使用00 狗头
+    uint8_t myMac[6] = {0x14, 0xE0, 0x81, 0x2f, 0x0c, 0x37};
+
+    // stm32可以使用唯一96Bit芯片序列号
+    // myMac[3] = *(uint8_t *)(UID_BASE + 0);
+    // myMac[4] = *(uint8_t *)(UID_BASE + 4);
+    // myMac[5] = *(uint8_t *)(UID_BASE + 8);
+
+    memcpy(netInfo.mac, myMac, sizeof(netInfo.mac));
+
+    // 用户也使用随机数来,需要支持rand函数才行
+    // ?但操作系统启动时间几乎时恒定的,ms时钟,可能造成随机数种子相同,随机数也一样的可能性
+    // srand(rt_tick_get()); // 设立随机数种子
+    // myMac[3] = rand() % 254 + 0;// 生成0~254的随机数
+    // srand(rt_tick_get()); // 设立随机数种子
+    // myMac[4] = rand() % 254 + 0;// 生成0~254的随机数
+    // srand(rt_tick_get()); // 设立随机数种子
+    // myMac[5] = rand() % 254 + 0;// 生成0~254的随机数
+
+    uint8_t ipStrArr[4] = {0};
+    inet_pton(AF_INET, "192.168.3.69", &ipStrArr);
+    memcpy(netInfo.ip, ipStrArr, 4);
+
+    inet_pton(AF_INET, "255.255.252.0", &ipStrArr);
+    memcpy(netInfo.sn, ipStrArr, 4);
+
+    inet_pton(AF_INET, "192.168.1.1", &ipStrArr);
+    memcpy(netInfo.gw, ipStrArr, 4);
+
+    inet_pton(AF_INET, "114.114.114.114", &ipStrArr);
+    memcpy(netInfo.dns, ipStrArr, 4);
+
+    netInfo.dhcp = NETINFO_DHCP; // 使能dhcp
+
+    RyanW5500Init(&netInfo);
+
+    ryanNetDev = netdev_get_by_name("RyanW5500"); // netdev
+    if (ryanNetDev == NULL)
+    {
+        ulog_e(TAG, "No device found");
+        return;
+    }
+
+    netdev_set_default(ryanNetDev);
+    netdev_set_status_callback(ryanNetDev, neDevStatusChangeCallback);
+
+    // while (!netdev_is_link_up(ryanNetDev))
+    // {
+    //     delay(200);
+    // }
+
+    return RT_EOK;
+}
+
+// TCP并发ECHO服务器
+void *deal_client_fun(void *arg)
+{
+
+    int fd = *(int *)arg; // 通过arg获得已连接套接字
+    char buf[256] = {0};
+
+    // struct timeval tv = {
+    //     .tv_sec = 2,
+    //     .tv_usec = 0};
+    // setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); // 设置接收超时
+
+    while (1)
+    {
+
+        // 获取客户端请求
+        int len = recv(fd, buf, sizeof(buf), 0);
+        if (len <= 0)
+        {
+            // 下列3种表示没问题,但需要推出发送
+            if ((errno == EAGAIN ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
+                 errno == EWOULDBLOCK || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
+                 errno == EINTR))        // 操作被信号中断
+            {
+                ulog_i(TAG, "接收超时...........");
+                continue;
+            }
+
+            ulog_w(TAG, "遇到错误, 退出 socket: %d, len: %d", fd, len);
+            close(fd);
+            return;
+        }
+
+        // rt_kprintf("客户端的请求为:%s recv:%d\n", buf, len);
+        send(fd, buf, len, 0); // 回应客户端
+    }
+}
+
+void tcpEchoTask(void *argument)
+{
+    int32_t port = (int32_t)argument;
+
+    int32_t ret;
+    uint16_t size = 0, sentsize = 0;
+    while (1)
+    {
+
+        // 创建一个tcp监听套接字
+        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
+
+        // 使用bind函数 给监听套接字 绑定固定的ip以及端口
+        struct sockaddr_in my_addr = {
+            .sin_family = AF_INET,                 // 协议族
+            .sin_port = htons(port),               // 端口号
+            .sin_addr.s_addr = htonl(INADDR_ANY)}; // 设置地址
+
+        bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
+
+        // 使用listen创建连接队列 主动变被动
+        listen(sockfd, 4);
+
+        while (1)
+        {
+            // 使用accpet函数从连接队列中 提取已完成的连接 得到已连接套接字
+            struct sockaddr_in cli_addr;
+            socklen_t cli_len = sizeof(cli_addr);
+            int new_fd = accept(sockfd, (struct sockaddr *)&cli_addr, &cli_len);
+            if (new_fd < 0)
+                break;
+
+            // new_fd代表的是客户端的连接   cli_addr存储是客户端的信息
+            rt_kprintf("客户端:%s:%hu连接了服务器\n", inet_ntoa(cli_addr.sin_addr.s_addr), ntohs(cli_addr.sin_port));
+
+            rt_thread_t idex = rt_thread_create("socket123123123", deal_client_fun, (void *)&new_fd, 2048, 12, 5);
+            if (idex != NULL)
+                rt_thread_startup(idex);
+        }
+
+        // 关闭监听套接字
+        close(sockfd);
+    }
+}
+
+void udpEchoServiceTask(void *argument)
+{
+    int32_t port = (int32_t)argument;
+
+    // 创建通讯的udp套接字(没有port, ip)
+    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+    printf("UDP套接字sockfd=%d\r\n", sockfd);
+
+    // 定义一个IPv4地址结构, 存放客户端的地址信息(本地主机)
+    struct sockaddr_in myAddr = {
+        .sin_family = AF_INET,
+        .sin_port = htons(port),
+        .sin_addr.s_addr = htonl(INADDR_ANY)};
+
+    // 给udp套接字 bind绑定一个固定的地址信息
+    bind(sockfd, (struct sockaddr *)&myAddr, sizeof(myAddr));
+
+    // 定义一个IPv4地址结构  存放发送者的数据
+    struct sockaddr_in from_addr;
+    socklen_t fromLen = sizeof(from_addr);
+    char buf[256] = {0};
+
+    while (1)
+    {
+        int len = recvfrom(sockfd, buf, sizeof(buf), 0,
+                           (struct sockaddr *)&from_addr, &fromLen);
+        if (len <= 0)
+        {
+            // 下列3种表示没问题,但需要推出发送
+            if ((errno == EAGAIN ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
+                 errno == EWOULDBLOCK || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
+                 errno == EINTR))        // 操作被信号中断
+            {
+                ulog_i(TAG, "接收超时...........");
+                continue;
+            }
+
+            ulog_w(TAG, "遇到错误, 退出 socket: %d, len: %d", sockfd, len);
+            break;
+        }
+
+        // printf("消息来自: %s : %hu\r\n", inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port));
+        // printf("len: %d msg:%s\r\n", len, buf);
+
+        sendto(sockfd, buf, len, 0, (struct sockaddr *)&from_addr, sizeof(from_addr));
+
+        memset(buf, 0, len);
+    }
+
+    // 关闭套接字
+    close(sockfd);
+}
+
+void multicastEchoServiceTask(void *argument)
+{
+    int32_t port = (int32_t)argument;
+
+    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+
+    // 让sockfd有一个固定的IP端口
+    struct sockaddr_in my_addr = {
+        .sin_family = AF_INET,
+        .sin_port = htons(port),
+        .sin_addr.s_addr = htonl(INADDR_ANY)};
+
+    bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
+
+    // 224.0.0.1 ~ 239.255.255.254 任意一个IP地址 都代表一个多播组
+    // 加入到多播组 224.0.0.252中
+    struct ip_mreq mreq = {
+        .imr_multiaddr.s_addr = inet_addr("224.1.1.1"),
+        .imr_interface.s_addr = htonl(INADDR_ANY)};
+
+    setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+
+    struct sockaddr_in from_addr = {0};
+    socklen_t fromLen = sizeof(from_addr);
+    char buf[256] = {0};
+
+    while (1)
+    {
+
+        int len = recvfrom(sockfd, buf, sizeof(buf), 0,
+                           (struct sockaddr *)&from_addr, &fromLen);
+        if (len <= 0)
+        {
+            // 下列3种表示没问题,但需要推出发送
+            if ((errno == EAGAIN ||      // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
+                 errno == EWOULDBLOCK || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
+                 errno == EINTR))        // 操作被信号中断
+            {
+                ulog_i(TAG, "multicast, 接收超时...........");
+                continue;
+            }
+
+            ulog_w(TAG, "multicast, 遇到错误, 退出 socket: %d, len: %d", sockfd, len);
+            break;
+        }
+
+        printf("multicast, 消息来自: %s : %hu\r\n", inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port));
+        printf("multicast, len: %d msg: %s\r\n", len, buf);
+
+        // 默认只会发送给多播组,这是w5500硬件限制的,如果想单播回复组播收到的信息,需要重新创建socket
+        // sendto(sockfd, "hellow", strlen("hellow"), 0, (struct sockaddr *)&from_addr, sizeof(from_addr));
+
+        int sockfd2 = socket(AF_INET, SOCK_DGRAM, 0);
+        struct sockaddr_in ser_addr = {.sin_family = AF_INET,
+                                       .sin_port = from_addr.sin_port,
+                                       .sin_addr.s_addr = from_addr.sin_addr.s_addr};
+        sendto(sockfd2, buf, len, 0, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
+        close(sockfd2); // 关闭套接字
+
+        memset(buf, 0, len);
+    }
+
+    close(sockfd);
+}
+
+static int w5500Static(int argc, char *argv[])
+{
+    // 测试netDev
+    netdev_dhcp_enabled(ryanNetDev, RT_FALSE);
+
+    //  设置网卡 IP 地址
+    uint32_t addr = inet_addr("192.168.3.69");
+    netdev_set_ipaddr(ryanNetDev, (const ip_addr_t *)&addr);
+
+    addr = inet_addr("192.168.1.1");
+    //  设置网卡网关地址
+    netdev_set_gw(ryanNetDev, (const ip_addr_t *)&addr);
+
+    addr = inet_addr("255.255.252.0");
+    //  设置网卡子网掩码地址
+    netdev_set_netmask(ryanNetDev, (const ip_addr_t *)&addr);
+
+    addr = inet_addr("114.114.114.114");
+    //  设置网卡子网掩码地址
+    netdev_set_dns_server(ryanNetDev, 0, (const ip_addr_t *)&addr);
+    ulog_i(TAG, "w5500Static");
+    return 0;
+}
+
+static int w5500Dhcp(int argc, char *argv[])
+{
+    netdev_dhcp_enabled(ryanNetDev, RT_TRUE);
+    ulog_i(TAG, "w5500Dhcp");
+    return 0;
+}
+
+static int w5500UdpClient(int argc, char *argv[])
+{
+    if (argc < 4)
+    {
+        ulog_i(TAG, "请输入udp服务器的IP, port ");
+        return 0;
+    }
+
+    char *serviceIP = argv[2];
+    int32_t servicePort = atoi(argv[3]);
+
+    // 创建通讯的udp套接字(没有port, ip)
+    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+    printf("UDP套接字sockfd=%d\r\n", sockfd);
+
+    // 定义一个IPv4地址结构, 存放服务器的地址信息(目标主机)
+    struct sockaddr_in ser_addr = {
+        .sin_family = AF_INET,
+        .sin_port = htons(servicePort),         // 将主机字节序转换成网络字节序
+        .sin_addr.s_addr = inet_addr(serviceIP) // 将服务器ip地址转换为32位整型数据
+    };
+
+    char buf[] = "This is a udp client test message";
+
+    sendto(sockfd, buf, strlen(buf),
+           0, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
+
+    // 关闭套接字
+    close(sockfd);
+    return 0;
+}
+
+static int w5500UdpService(int argc, char *argv[])
+{
+    if (argc < 3)
+    {
+        ulog_i(TAG, "请输入udpService的port ");
+        return 0;
+    }
+
+    int32_t port = atoi(argv[2]);
+    static rt_thread_t hid = NULL;
+    if (NULL != hid)
+    {
+        ulog_w(TAG, "udp服务器已启动,请勿重复创建");
+        return -1;
+    }
+
+    // 创建WIZnet SPI RX线程
+    hid = rt_thread_create("udpService",       // 线程name
+                           udpEchoServiceTask, // 线程入口函数
+                           (void *)port,       // 线程入口函数参数
+                           2048,               // 线程栈大小
+                           18,                 // 线程优先级
+                           5);                 // 线程时间片
+
+    if (NULL != hid)
+        rt_thread_startup(hid);
+    else
+        ulog_w(TAG, "创建udp echo线程失败");
+
+    return 0;
+}
+
+static int w5500TcpClient(int argc, char *argv[])
+{
+    if (argc < 4)
+    {
+        ulog_i(TAG, "请输入tcp服务器的IP, port ");
+        return 0;
+    }
+
+    char *serviceIP = argv[2];
+    int32_t servicePort = atoi(argv[3]);
+
+    int32_t result = 0;
+
+    // 创建一个TCP套接字 SOCK_STREAM
+    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
+    printf("sockfd = %d\n", sockfd);
+
+    // bind是可选的,这里使用,纯粹为了演示
+    // !此库w5500实现, 不推荐使用bind,使用bind会释放之前申请socket,重新申请。这是因为w5500特性造成
+    struct sockaddr_in my_addr = {
+        .sin_family = AF_INET,
+        .sin_port = htons(45876),
+        .sin_addr.s_addr = htonl(INADDR_ANY)};
+    bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
+
+    // connect链接服务器
+    struct sockaddr_in ser_addr = {
+        .sin_family = AF_INET,
+        .sin_port = htons(servicePort),         // 服务器的端口
+        .sin_addr.s_addr = inet_addr(serviceIP) // 服务器的IP
+    };
+
+    // 如果sockfd没有绑定固定的IP以及端口
+    // 正常情况,在调用connect时候 系统给sockfd分配自身IP以及随机端口
+    // 堆区此库W5500实现,是在socket时进行绑定的
+    result = connect(sockfd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
+    if (0 != result)
+    {
+        ulog_i(TAG, "connect错误, 目标ip: %s, 目标端口: %d, err code: %s", serviceIP, servicePort, strerror(errno));
+        return -1;
+    }
+
+    char buf[] = "This is a tdp client test message";
+
+    result = send(sockfd, buf, strlen(buf), 0);
+    if (result < 0)
+    {
+        ulog_i(TAG, "send错误, 目标ip: %s, 目标端口: %s, err code: %s", serviceIP, servicePort, strerror(errno));
+        return -1;
+    }
+
+    // 关闭套接字
+    close(sockfd);
+    return 0;
+}
+
+/**
+ * @brief
+ * !注意: 由于W5500一个socket只能listen一个连接
+ * !RyanW5500库实现的listen多连接,原有服务器套接字不使用,
+ * !accept时会保证服务器socket链表中有一个套接字进行listen,当有客户端连接时,返回此套接字
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+static int w5500tcpService(int argc, char *argv[])
+{
+    if (argc < 3)
+    {
+        ulog_i(TAG, "请输入tcpService的port ");
+        return 0;
+    }
+
+    int32_t port = atoi(argv[2]);
+
+    static rt_thread_t hid = NULL;
+    if (NULL != hid)
+    {
+        ulog_w(TAG, "tcp服务器已启动,请勿重复创建");
+        return -1;
+    }
+
+    // 创建WIZnet SPI RX线程
+    hid = rt_thread_create("tcpService", // 线程name
+                           tcpEchoTask,  // 线程入口函数
+                           (void *)port, // 线程入口函数参数
+                           2048,         // 线程栈大小
+                           16,           // 线程优先级
+                           5);           // 线程时间片
+
+    if (hid != NULL)
+        rt_thread_startup(hid);
+    else
+        ulog_w(TAG, "创建tcp echo线程失败");
+    return 0;
+}
+
+static int w5500Broadcast(int argc, char *argv[])
+{
+
+    if (argc < 4)
+    {
+        ulog_i(TAG, "请输入broadcast发送的port和消息内容 ");
+        return 0;
+    }
+
+    int32_t port = atoi(argv[2]);
+    char *msg = argv[3];
+
+    // udp支持广播
+    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+
+    // 让sockfd支持广播
+    int yes = 1;
+    setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));
+
+    // 发送广播地址(目的地址 是广播地址)
+    struct sockaddr_in dst_addr = {
+        .sin_family = AF_INET,
+        .sin_port = htons(port),
+        .sin_addr.s_addr = inet_addr("255.255.255.255")};
+
+    sendto(sockfd, msg, strlen(msg), 0,
+           (struct sockaddr *)&dst_addr, sizeof(dst_addr));
+
+    close(sockfd);
+    return 0;
+}
+
+/**
+ * @brief
+ * !注意:RyanW5500组播实现不支持加入多个组播组,这是由W5500硬件限制的,和tcp服务器一样。
+ * !虽然可以通过申请多个socket, 再将数据合并实现,但考虑多组播功能并不常用,且实现较为复杂占资源,暂时没有实现多组播
+ * !目前如果需要加入多个组播的话,就申请多个socket分别加入组播组吧
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+static int w5500Multicast(int argc, char *argv[])
+{
+
+    if (argc < 3)
+    {
+        ulog_i(TAG, "请输入multicast发送的port ");
+        return 0;
+    }
+
+    int32_t port = atoi(argv[2]);
+
+    static rt_thread_t hid = NULL;
+    if (NULL != hid)
+    {
+        ulog_w(TAG, "组播echo服务器已启动,请勿重复创建");
+        return -1;
+    }
+
+    // 创建WIZnet SPI RX线程
+    hid = rt_thread_create("multicast",              // 线程name
+                           multicastEchoServiceTask, // 线程入口函数
+                           (void *)port,             // 线程入口函数参数
+                           2048,                     // 线程栈大小
+                           19,                       // 线程优先级
+                           5);                       // 线程时间片
+
+    if (hid != NULL)
+        rt_thread_startup(hid);
+    else
+        ulog_w(TAG, "创建udp echo线程失败");
+
+    ulog_i(TAG, "multicast 地址: %s, port: %d", "224.0.0.252", port);
+    return 0;
+}
+
+static int w5500dhcpLeasetime(int argc, char *argv[])
+{
+    if (RT_TRUE != netdev_is_dhcp_enabled(ryanNetDev))
+    {
+        ulog_i(TAG, "dhcp服务未启动, 目前处于静态ip状态");
+        return 0;
+    }
+
+    ulog_i(TAG, "租期总时长:%d s, 剩余时长: %d s", getDHCPLeaseTime() / 1000, getDHCPRemainLeaseTime() / 1000);
+    return 0;
+}
+
+static int w5500GetNetInfo(int argc, char *argv[])
+{
+    uint8_t tmpstr[6] = {0};
+    wiz_NetInfo netinfo = {0};
+    // Display Network Information
+    ctlwizchip(CW_GET_ID, (void *)tmpstr);
+    ctlnetwork(CN_GET_NETINFO, (void *)&netinfo); // 获取网络信息
+
+    if (NETINFO_DHCP == netinfo.dhcp)
+        printf("\r\n=== %s NET CONF : DHCP ===\r\n", (char *)tmpstr);
+    else
+        printf("\r\n=== %s NET CONF : Static ===\r\n", (char *)tmpstr);
+
+    printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", netinfo.mac[0], netinfo.mac[1], netinfo.mac[2],
+           netinfo.mac[3], netinfo.mac[4], netinfo.mac[5]);
+    printf("SIP: %d.%d.%d.%d\r\n", netinfo.ip[0], netinfo.ip[1], netinfo.ip[2], netinfo.ip[3]);
+    printf("GAR: %d.%d.%d.%d\r\n", netinfo.gw[0], netinfo.gw[1], netinfo.gw[2], netinfo.gw[3]);
+    printf("SUB: %d.%d.%d.%d\r\n", netinfo.sn[0], netinfo.sn[1], netinfo.sn[2], netinfo.sn[3]);
+    printf("DNS: %d.%d.%d.%d\r\n", netinfo.dns[0], netinfo.dns[1], netinfo.dns[2], netinfo.dns[3]);
+    printf("===========================\r\n");
+
+    return 0;
+}
+
+static int w5500GetHostByName(int argc, char *argv[])
+{
+    if (argc < 4)
+    {
+        ulog_i(TAG, "请版本、带解析的域名信息。 版本1使用线程安全版本, 0非线程安全版本");
+        return 0;
+    }
+
+    uint8_t choice = atoi(argv[2]);
+    char *nameStr = argv[3];
+
+    if (0 == choice)
+    {
+
+        struct hostent *hent;
+        hent = gethostbyname(nameStr);
+
+        if (hent == NULL)
+        {
+            printf("ERROR: gethostbyname error for hostname: %s\n", nameStr);
+            return 0;
+        }
+
+        printf("name: %s, addrtype: %d(AF_INET:%d), len:%d\n",
+               hent->h_name, hent->h_addrtype, AF_INET,
+               hent->h_length);
+
+        for (uint8_t i = 0; hent->h_aliases[i]; i++)
+            printf("alias hostname: %s\n", hent->h_aliases[i]);
+
+        for (uint8_t i = 0; hent->h_addr_list[i]; i++)
+            printf("host addr is: %s\n", inet_ntoa(*(struct in_addr *)hent->h_addr_list[i]));
+    }
+
+    else
+    {
+        char buf[1024];
+        int ret;
+        struct hostent hostinfo, *phost;
+
+        if (gethostbyname_r(nameStr, &hostinfo, buf, sizeof(buf), &phost, &ret))
+        {
+            printf("ERROR:gethostbyname(%s) ret:%d\n", nameStr, ret);
+            return 0;
+        }
+
+        printf("name: %s, addrtype: %d(AF_INET:%d), len:%d\n",
+               phost->h_name, phost->h_addrtype, AF_INET,
+               phost->h_length);
+
+        for (uint8_t i = 0; hostinfo.h_aliases[i]; i++)
+            printf("alias hostname: %s\n", hostinfo.h_aliases[i]);
+
+        for (uint8_t i = 0; hostinfo.h_addr_list[i]; i++)
+            printf("host addr is: %s\n", inet_ntoa(*((struct in_addr *)hostinfo.h_addr_list[i])));
+    }
+
+    return 0;
+}
+
+static int w5500GetAddrInfo(int argc, char *argv[])
+{
+    if (argc < 4)
+    {
+        ulog_i(TAG, "请输入要解析的域名和端口");
+        return 0;
+    }
+
+    char *nameStr = argv[2];
+    char *namePort = argv[3];
+
+    struct addrinfo *addrList = NULL,
+                    *aip;
+
+    struct addrinfo hints = {0};
+
+    int result = getaddrinfo(nameStr, namePort, &hints, &addrList);
+    if (0 != result)
+    {
+        printf("ERROR: getaddrinfo(%s) ret:%d\n", nameStr, result);
+        return 0;
+    }
+
+    struct sockaddr_in *sinp;
+    const char *addr;
+    char buf[40];
+
+    for (aip = addrList; aip != NULL; aip = aip->ai_next)
+    {
+        sinp = (struct sockaddr_in *)aip->ai_addr;
+        addr = inet_ntop(AF_INET, &sinp->sin_addr, buf, sizeof(buf));
+        printf(" addr = %s, port = %d\n", addr ? addr : "unknow ", ntohs(sinp->sin_port));
+    }
+
+    if (NULL != addrList)
+        freeaddrinfo(addrList);
+
+    return 0;
+}
+
+/**
+ * @brief mqtt msh命令
+ *
+ */
+struct RyanMqttCmdDes
+{
+    const char *cmd;
+    const char *explain;
+    int (*fun)(int argc, char *argv[]);
+};
+
+static int w5500Help(int argc, char *argv[]);
+
+static const struct RyanMqttCmdDes cmdTab[] =
+    {
+        {"help", "打印帮助信息", w5500Help},
+        {"start", "打印帮助信息", w5500Start},
+        {"static", "设置w5500静态地址", w5500Static},
+        {"dhcp", "设置w5500 dhcp", w5500Dhcp},
+        {"udpClient", "w5500 udp客户端 param: ip, port", w5500UdpClient},
+        {"udpService", "w5500 udp echo服务器 param: port", w5500UdpService},
+        {"tcpClient", "w5500 tcp客户端 param: ip, port", w5500TcpClient},
+        {"tcpService", "w5500 tcp 多线程echo服务器 param: port", w5500tcpService},
+        {"broadcast", "w5500 广播 param: port, msg", w5500Broadcast},
+        {"multicast", "w5500 多播 echo服务器 param: port", w5500Multicast},
+
+        {"dhcpLease", "w5500 获取dhcp租期和剩余时间", w5500dhcpLeasetime},
+        {"netInfo", "w5500 获取芯片内部配置信息", w5500GetNetInfo},
+        {"gethostbyname", "w5500 根据域名解析地址信息", w5500GetHostByName},
+        {"getaddrinfo", "w5500 根据域名获取IP等信息", w5500GetAddrInfo},
+
+};
+
+static int w5500Help(int argc, char *argv[])
+{
+
+    for (uint8_t i = 0; i < sizeof(cmdTab) / sizeof(cmdTab[0]); i++)
+        rt_kprintf("w5500 %-16s %s\r\n", cmdTab[i].cmd, cmdTab[i].explain);
+
+    return 0;
+}
+
+static int RyanMqttMsh(int argc, char *argv[])
+{
+    int32_t i = 0,
+            result = 0;
+    struct RyanMqttCmdDes *runCmd = NULL;
+
+    if (argc == 1)
+    {
+        w5500Help(argc, argv);
+        return 0;
+    }
+
+    for (i = 0; i < sizeof(cmdTab) / sizeof(cmdTab[0]); i++)
+    {
+        if (rt_strcmp(cmdTab[i].cmd, argv[1]) == 0)
+        {
+            runCmd = &cmdTab[i];
+            break;
+        }
+    }
+
+    if (runCmd == NULL)
+    {
+        w5500Help(argc, argv);
+        return 0;
+    }
+
+    if (runCmd->fun != NULL)
+        result = runCmd->fun(argc, argv);
+
+    return 0;
+}
+
+#if defined(RT_USING_MSH)
+MSH_CMD_EXPORT_ALIAS(RyanMqttMsh, w5500, RyanMqtt command);
+#endif

+ 762 - 0
ioLibrary/DHCP/wizchip_dhcp.c

@@ -0,0 +1,762 @@
+
+#include "wizchip_socket.h"
+#include "wizchip_dhcp.h"
+
+#define DBG_ENABLE
+
+#define DBG_SECTION_NAME "dhcp"
+#define DBG_LEVEL DBG_WARNING
+#define DBG_COLOR
+
+#include <stdio.h>
+#include <string.h>
+#include "RyanW5500Store.h"
+
+/*DHCP 状态机。*/
+typedef enum
+{
+    STATE_DHCP_INIT = 0,      // 初始化
+    STATE_DHCP_DISCOVER = 1,  // 发送 DISCOVER 并等待 OFFER
+    STATE_DHCP_REQUEST = 2,   // 发送请求并等待 ACK 或 NACK
+    STATE_DHCP_LEASED = 3,    // 接收D ACK和IP租用
+    STATE_DHCP_REREQUEST = 4, // 发送维护租用 IP 的请求
+    STATE_DHCP_RELEASE = 5,   // 没用
+    STATE_DHCP_STOP = 6,      // 停止处理 DHCP
+} wizchipDhcpState_e;
+
+#define DHCP_FLAGSBROADCAST 0x8000 //@ref RIP_MSG 中标志的广播值
+#define DHCP_FLAGSUNICAST 0x0000   //@ref RIP_MSG 中标志的单播值
+
+/*DHCP 消息 OP 代码*/
+#define DHCP_BOOTREQUEST 1 // 在@ref RIP_MSG 的操作中使用的请求消息
+#define DHCP_BOOTREPLY 2   // 回复消息使用了@ref RIP_MSG 的 i op
+
+/*DHCP 消息类型*/
+#define DHCP_DISCOVER 1 // 在@ref RIP_MSG 的 OPT 中发现消息
+#define DHCP_OFFER 2    //@ref RIP_MSG 的 OPT 中的 OFFER 消息
+#define DHCP_REQUEST 3  //@ref RIP_MSG 的 OPT 中的请求消息
+#define DHCP_DECLINE 4  //@ref RIP_MSG 的 OPT 中的 DECLINE 消息
+#define DHCP_ACK 5      //@ref RIP_MSG 的 OPT 中的 ACK 消息
+#define DHCP_NAK 6      //@ref RIP_MSG 的 OPT 中的 NACK 消息
+#define DHCP_RELEASE 7  // 在@ref RIP_MSG 的 OPT 中释放消息。没用
+#define DHCP_INFORM 8   //@ref RIP_MSG 的 OPT 中的 INFORM 消息。没用
+
+#define DHCP_HTYPE10MB 1  // 用于@ref RIP_MSG 类型
+#define DHCP_HTYPE100MB 2 // 用于@ref RIP_MSG 类型
+
+#define DHCP_HLENETHERNET 6 // 在@ref RIP_MSG 的 hlen 中使用
+#define DHCP_HOPS 0         // 在@ref RIP_MSG 的跃点中使用
+#define DHCP_SECS 0         // 在 @ref RIP_MSG 的秒中使用
+
+#define INFINITE_LEASETIME 0xffffffff // 无限租用时间
+
+#define OPT_SIZE 312                  ///@ref RIP_MSG 的最大 OPT 大小
+#define RIP_MSG_SIZE (236 + OPT_SIZE) ///@ref RIP_MSG 的最大大小
+
+/**
+ *@brief DHCP 选项和值(参见 RFC1533)
+ *
+ */
+enum
+{
+    padOption = 0,
+    subnetMask = 1,
+    timerOffset = 2,
+    routersOnSubnet = 3,
+    timeServer = 4,
+    nameServer = 5,
+    dns = 6,
+    logServer = 7,
+    cookieServer = 8,
+    lprServer = 9,
+    impressServer = 10,
+    resourceLocationServer = 11,
+    hostName = 12,
+    bootFileSize = 13,
+    meritDumpFile = 14,
+    domainName = 15,
+    swapServer = 16,
+    rootPath = 17,
+    extentionsPath = 18,
+    IPforwarding = 19,
+    nonLocalSourceRouting = 20,
+    policyFilter = 21,
+    maxDgramReasmSize = 22,
+    defaultIPTTL = 23,
+    pathMTUagingTimeout = 24,
+    pathMTUplateauTable = 25,
+    ifMTU = 26,
+    allSubnetsLocal = 27,
+    broadcastAddr = 28,
+    performMaskDiscovery = 29,
+    maskSupplier = 30,
+    performRouterDiscovery = 31,
+    routerSolicitationAddr = 32,
+    staticRoute = 33,
+    trailerEncapsulation = 34,
+    arpCacheTimeout = 35,
+    ethernetEncapsulation = 36,
+    tcpDefaultTTL = 37,
+    tcpKeepaliveInterval = 38,
+    tcpKeepaliveGarbage = 39,
+    nisDomainName = 40,
+    nisServers = 41,
+    ntpServers = 42,
+    vendorSpecificInfo = 43,
+    netBIOSnameServer = 44,
+    netBIOSdgramDistServer = 45,
+    netBIOSnodeType = 46,
+    netBIOSscope = 47,
+    xFontServer = 48,
+    xDisplayManager = 49,
+    dhcpRequestedIPaddr = 50,
+    dhcpIPaddrLeaseTime = 51,
+    dhcpOptionOverload = 52,
+    dhcpMessageType = 53,
+    dhcpServerIdentifier = 54,
+    dhcpParamRequest = 55,
+    dhcpMsg = 56,
+    dhcpMaxMsgSize = 57,
+    dhcpT1value = 58,
+    dhcpT2value = 59,
+    dhcpClassIdentifier = 60,
+    dhcpClientIdentifier = 61,
+    endOption = 255
+};
+
+/**
+ *@brief DHCP消息格式
+ */
+typedef struct
+{
+    uint8_t op;            //@ref DHCP_BOOTREQUEST 或 @ref DHCP_BOOTREPLY
+    uint8_t htype;         //@ref DHCP_HTYPE10MB 或 @ref DHCP_HTYPE100MB
+    uint8_t hlen;          //@ref DHCP_HLENETHERNET
+    uint8_t hops;          //@ref DHCP_HOPS
+    uint32_t xid;          //@ref DHCP_XID 这会在每个 DHCP 事务中增加一个。
+    uint16_t secs;         //@ref DHCP_SECS
+    uint16_t flags;        //@ref DHCP_FLAGSBROADCAST 或 @ref DHCP_FLAGSUNICAST
+    uint8_t ciaddr[4];     //@ref 向 DHCP 服务器请求 IP
+    uint8_t yiaddr[4];     //@ref 从 DHCP 服务器提供的 IP
+    uint8_t siaddr[4];     // 没用
+    uint8_t giaddr[4];     // 没用
+    uint8_t chaddr[16];    // DHCP 客户端 6 字节 MAC 地址。其他填充为零
+    uint8_t sname[64];     // 没用
+    uint8_t file[128];     // 没用
+    uint8_t OPT[OPT_SIZE]; // 选项
+} RIP_MSG;
+
+uint8_t DHCP_SOCKET; // DHCP 的套接字号
+
+uint8_t DHCP_SIP[4];      // DHCP 服务器 IP 地址
+uint8_t DHCP_REAL_SIP[4]; // 用于在几个 DHCP 服务器中提取我的 DHCP 服务器
+// 来自 DHCP 服务器的网络信息
+uint8_t OLD_allocated_ip[4] = {0}; // 以前的 IP 地址
+
+wizchipDhcpState_e dhcp_state = STATE_DHCP_INIT; // DHCP 状态
+// INFINITE_LEASETIME
+platformTimer_t dhcp_lease_time = {0};
+
+uint32_t DHCP_XID; // 任何数字
+
+RIP_MSG *pDHCPMSG; // DHCP 处理的缓冲区指针
+
+uint8_t HOST_NAME[] = DCHP_HOST_NAME;
+
+char NibbleToHex(uint8_t nibble)
+{
+    nibble &= 0x0F;
+    if (nibble <= 9)
+        return nibble + '0';
+    else
+        return nibble + ('A' - 0x0A);
+}
+
+/**
+ *@brief 生成通用dhcp消息
+ *
+ */
+void makeDHCPMSG(void)
+{
+    uint8_t bk_mac[6];
+    uint8_t *ptmp;
+    uint8_t i;
+    getSHAR(bk_mac);
+    pDHCPMSG->op = DHCP_BOOTREQUEST;
+    pDHCPMSG->htype = DHCP_HTYPE10MB;
+    pDHCPMSG->hlen = DHCP_HLENETHERNET;
+    pDHCPMSG->hops = DHCP_HOPS;
+
+    ptmp = (uint8_t *)(&pDHCPMSG->xid);
+    *(ptmp + 0) = (uint8_t)((DHCP_XID & 0xFF000000) >> 24);
+    *(ptmp + 1) = (uint8_t)((DHCP_XID & 0x00FF0000) >> 16);
+    *(ptmp + 2) = (uint8_t)((DHCP_XID & 0x0000FF00) >> 8);
+    *(ptmp + 3) = (uint8_t)((DHCP_XID & 0x000000FF) >> 0);
+
+    pDHCPMSG->secs = DHCP_SECS;
+    ptmp = (uint8_t *)(&pDHCPMSG->flags);
+    *(ptmp + 0) = (uint8_t)((DHCP_FLAGSBROADCAST & 0xFF00) >> 8);
+    *(ptmp + 1) = (uint8_t)((DHCP_FLAGSBROADCAST & 0x00FF) >> 0);
+
+    memset(pDHCPMSG->ciaddr, 0, 4);
+    memset(pDHCPMSG->yiaddr, 0, 4);
+    memset(pDHCPMSG->siaddr, 0, 4);
+    memset(pDHCPMSG->giaddr, 0, 4);
+
+    memcpy(pDHCPMSG->chaddr, gWIZNETINFO.mac, 6);
+
+    for (i = 6; i < 16; i++)
+        pDHCPMSG->chaddr[i] = 0;
+    for (i = 0; i < 64; i++)
+        pDHCPMSG->sname[i] = 0;
+    for (i = 0; i < 128; i++)
+        pDHCPMSG->file[i] = 0;
+
+    // 魔法饼干
+    pDHCPMSG->OPT[0] = (uint8_t)((MAGIC_COOKIE & 0xFF000000) >> 24);
+    pDHCPMSG->OPT[1] = (uint8_t)((MAGIC_COOKIE & 0x00FF0000) >> 16);
+    pDHCPMSG->OPT[2] = (uint8_t)((MAGIC_COOKIE & 0x0000FF00) >> 8);
+    pDHCPMSG->OPT[3] = (uint8_t)(MAGIC_COOKIE & 0x000000FF) >> 0;
+}
+
+/*SEND DHCP DISCOVER*/
+/**
+ *@brief 发送dhcp discover消息
+ *
+ */
+void send_DHCP_DISCOVER(void)
+{
+    uint16_t i;
+    uint8_t ip[4] = {255, 255, 255, 255};
+    uint16_t k = 0;
+
+    makeDHCPMSG();
+
+    memset(DHCP_SIP, 0, 4);
+    memset(DHCP_REAL_SIP, 0, 4);
+
+    k = 4; // 因为 MAGIC_COOKIE 已经由 makeDHCPMSG() 生成
+
+    // 选项请求参数
+    pDHCPMSG->OPT[k++] = dhcpMessageType;
+    pDHCPMSG->OPT[k++] = 0x01;
+    pDHCPMSG->OPT[k++] = DHCP_DISCOVER;
+
+    // 客户端标识符
+    pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
+    pDHCPMSG->OPT[k++] = 0x07;
+    pDHCPMSG->OPT[k++] = 0x01;
+
+    memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.mac, 6);
+    k += 6;
+
+    // 主机名
+    pDHCPMSG->OPT[k++] = hostName;
+    pDHCPMSG->OPT[k++] = 0; // 填充零长度的主机名
+    for (i = 0; HOST_NAME[i] != 0; i++)
+        pDHCPMSG->OPT[k++] = HOST_NAME[i];
+    pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[3] >> 4);
+    pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[3]);
+    pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[4] >> 4);
+    pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[4]);
+    pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[5] >> 4);
+    pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[5]);
+    pDHCPMSG->OPT[k - (i + 6 + 1)] = i + 6; // 主机名长度
+
+    pDHCPMSG->OPT[k++] = dhcpParamRequest;
+    pDHCPMSG->OPT[k++] = 0x06; // 请求长度
+    pDHCPMSG->OPT[k++] = subnetMask;
+    pDHCPMSG->OPT[k++] = routersOnSubnet;
+    pDHCPMSG->OPT[k++] = dns;
+    pDHCPMSG->OPT[k++] = domainName;
+    pDHCPMSG->OPT[k++] = dhcpT1value;
+    pDHCPMSG->OPT[k++] = dhcpT2value;
+    pDHCPMSG->OPT[k++] = endOption;
+
+    for (i = k; i < OPT_SIZE; i++)
+        pDHCPMSG->OPT[i] = 0;
+
+    LOG_D("> Send DHCP_DISCOVER");
+
+    // 广播发送
+    wizchip_sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
+}
+
+/**
+ *@brief 发送请求地址租用 request报文
+ *
+ */
+void send_DHCP_REQUEST(void)
+{
+    int i;
+    uint16_t k = 0;
+    uint8_t ip[4] = {255, 255, 255, 255};
+
+    makeDHCPMSG();
+
+    if (dhcp_state == STATE_DHCP_LEASED || dhcp_state == STATE_DHCP_REREQUEST)
+    {
+        *((uint8_t *)(&pDHCPMSG->flags)) = ((DHCP_FLAGSUNICAST & 0xFF00) >> 8);
+        *((uint8_t *)(&pDHCPMSG->flags) + 1) = (DHCP_FLAGSUNICAST & 0x00FF);
+
+        memcpy(pDHCPMSG->ciaddr, gWIZNETINFO.ip, 4);
+        memcpy(ip, DHCP_SIP, 4);
+    }
+
+    k = 4; // 因为 MAGIC_COOKIE 已经由 makeDHCPMSG() 生成
+
+    // 选项请求参数。
+    pDHCPMSG->OPT[k++] = dhcpMessageType;
+    pDHCPMSG->OPT[k++] = 0x01;
+    pDHCPMSG->OPT[k++] = DHCP_REQUEST;
+
+    pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
+    pDHCPMSG->OPT[k++] = 0x07;
+    pDHCPMSG->OPT[k++] = 0x01;
+
+    memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.mac, 6);
+    k += 6;
+
+    if (ip[3] == 255) // 如果(dchp_state == STATE_DHCP_LEASED || dchp_state == DHCP_REREQUEST_STATE)
+    {
+        pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
+        pDHCPMSG->OPT[k++] = 0x04;
+
+        memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.ip, 4);
+        k += 4;
+
+        pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
+        pDHCPMSG->OPT[k++] = 0x04;
+
+        memcpy(pDHCPMSG->OPT + k, DHCP_SIP, 4);
+        k += 4;
+    }
+
+    // 主机名
+    pDHCPMSG->OPT[k++] = hostName;
+    pDHCPMSG->OPT[k++] = 0; // 主机名长度
+    for (i = 0; HOST_NAME[i] != 0; i++)
+        pDHCPMSG->OPT[k++] = HOST_NAME[i];
+    pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[3] >> 4);
+    pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[3]);
+    pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[4] >> 4);
+    pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[4]);
+    pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[5] >> 4);
+    pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[5]);
+    pDHCPMSG->OPT[k - (i + 6 + 1)] = i + 6; // 主机名长度
+
+    pDHCPMSG->OPT[k++] = dhcpParamRequest;
+    pDHCPMSG->OPT[k++] = 0x08;
+    pDHCPMSG->OPT[k++] = subnetMask;
+    pDHCPMSG->OPT[k++] = routersOnSubnet;
+    pDHCPMSG->OPT[k++] = dns;
+    pDHCPMSG->OPT[k++] = domainName;
+    pDHCPMSG->OPT[k++] = dhcpT1value;
+    pDHCPMSG->OPT[k++] = dhcpT2value;
+    pDHCPMSG->OPT[k++] = performRouterDiscovery;
+    pDHCPMSG->OPT[k++] = staticRoute;
+    pDHCPMSG->OPT[k++] = endOption;
+
+    for (i = k; i < OPT_SIZE; i++)
+        pDHCPMSG->OPT[i] = 0;
+
+    LOG_D("> Send DHCP_REQUEST");
+
+    wizchip_sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
+}
+
+/*发送 DHCP DHCPDECLINE*/
+void send_DHCP_DECLINE(void)
+{
+    int i;
+    uint8_t ip[4];
+    uint16_t k = 0;
+
+    makeDHCPMSG();
+
+    k = 4; // 因为 MAGIC_COOKIE 已经由 makeDHCPMSG() 生成
+
+    *((uint8_t *)(&pDHCPMSG->flags)) = ((DHCP_FLAGSUNICAST & 0xFF00) >> 8);
+    *((uint8_t *)(&pDHCPMSG->flags) + 1) = (DHCP_FLAGSUNICAST & 0x00FF);
+
+    // 选项请求参数。
+    pDHCPMSG->OPT[k++] = dhcpMessageType;
+    pDHCPMSG->OPT[k++] = 0x01;
+    pDHCPMSG->OPT[k++] = DHCP_DECLINE;
+
+    pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
+    pDHCPMSG->OPT[k++] = 0x07;
+    pDHCPMSG->OPT[k++] = 0x01;
+
+    memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.mac, 6);
+    k += 6;
+
+    pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
+    pDHCPMSG->OPT[k++] = 0x04;
+
+    memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.ip, 4);
+    k += 4;
+
+    pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
+    pDHCPMSG->OPT[k++] = 0x04;
+
+    memcpy(pDHCPMSG->OPT + k, DHCP_SIP, 4);
+    k += 4;
+
+    pDHCPMSG->OPT[k++] = endOption;
+
+    for (i = k; i < OPT_SIZE; i++)
+        pDHCPMSG->OPT[i] = 0;
+
+    // 发送广播包
+    memset(ip, 0xFF, 4);
+
+    LOG_D("> Send DHCP_DECLINE");
+
+    wizchip_sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
+}
+
+/**
+ *@brief 解析回复的dhcp报文
+ *
+ *@return int8_t
+ */
+int8_t parseDHCPMSG(void)
+{
+    uint8_t svr_addr[6];
+    uint16_t svr_port;
+    uint16_t len;
+
+    uint8_t *p;
+    uint8_t *e;
+    uint8_t type = 0;
+    uint8_t opt_len;
+    len = getSn_RX_RSR(DHCP_SOCKET);
+    if (len <= 0)
+        return 0;
+
+    len = wizchip_recvfrom(DHCP_SOCKET, (uint8_t *)pDHCPMSG, len, svr_addr, &svr_port);
+    LOG_D("DHCP message : %d.%d.%d.%d(%d) %d received. ", svr_addr[0], svr_addr[1], svr_addr[2], svr_addr[3], svr_port, len);
+
+    if (DHCP_SERVER_PORT != svr_port)
+        return 0;
+
+    // 校验mac地址
+    if (0 != memcmp(gWIZNETINFO.mac, pDHCPMSG->chaddr, sizeof(gWIZNETINFO.mac)))
+    {
+        LOG_D("No My DHCP Message. This message is ignored.");
+        return 0;
+    }
+
+    // 比较 DHCP 服务器 ip 地址
+    if ((DHCP_SIP[0] != 0) || (DHCP_SIP[1] != 0) || (DHCP_SIP[2] != 0) || (DHCP_SIP[3] != 0))
+    {
+        if (0 != memcmp(DHCP_SIP, svr_addr, sizeof(DHCP_SIP)) &&
+            0 != memcmp(DHCP_REAL_SIP, svr_addr, sizeof(DHCP_REAL_SIP)))
+        {
+            LOG_D("Another DHCP sever send a response message. This is ignored.");
+            return 0;
+        }
+    }
+
+    p = (uint8_t *)(&pDHCPMSG->op);
+    p = p + 240; // 240 = sizeof(RIP_MSG) + RIP_MSG.opt 中的 MAGIC_COOKIE 大小 -sizeof(RIP_MSG.opt)
+    e = p + (len - 240);
+
+    while (p < e)
+    {
+        switch (*p)
+        {
+
+        case endOption:
+            p = e; // 中断 while(p < e)
+            break;
+
+        case padOption:
+            p++;
+            break;
+
+        case dhcpMessageType:
+            p++;
+            p++;
+            type = *p++;
+            break;
+        case subnetMask:
+            p++;
+            p++;
+
+            gWIZNETINFO.sn[0] = *p++;
+            gWIZNETINFO.sn[1] = *p++;
+            gWIZNETINFO.sn[2] = *p++;
+            gWIZNETINFO.sn[3] = *p++;
+            break;
+
+        case routersOnSubnet:
+            p++;
+            opt_len = *p++;
+
+            gWIZNETINFO.gw[0] = *p++;
+            gWIZNETINFO.gw[1] = *p++;
+            gWIZNETINFO.gw[2] = *p++;
+            gWIZNETINFO.gw[3] = *p++;
+
+            p = p + (opt_len - 4);
+            break;
+
+        case dns:
+            p++;
+            opt_len = *p++;
+
+            gWIZNETINFO.dns[0] = *p++;
+            gWIZNETINFO.dns[1] = *p++;
+            gWIZNETINFO.dns[2] = *p++;
+            gWIZNETINFO.dns[3] = *p++;
+
+            p = p + (opt_len - 4);
+            break;
+
+        case dhcpIPaddrLeaseTime:
+            p++;
+            opt_len = *p++;
+
+            uint32_t dhcpLeaseTime = 0;
+            dhcpLeaseTime = *p++;
+            dhcpLeaseTime = (dhcpLeaseTime << 8) + *p++;
+            dhcpLeaseTime = (dhcpLeaseTime << 8) + *p++;
+            dhcpLeaseTime = (dhcpLeaseTime << 8) + *p++;
+            platformTimerCutdown(&dhcp_lease_time, dhcpLeaseTime * 1000);
+
+            break;
+        case dhcpServerIdentifier:
+            p++;
+            opt_len = *p++;
+            DHCP_SIP[0] = *p++;
+            DHCP_SIP[1] = *p++;
+            DHCP_SIP[2] = *p++;
+            DHCP_SIP[3] = *p++;
+
+            memcpy(DHCP_REAL_SIP, svr_addr, 4);
+
+            break;
+
+        default:
+            p++;
+            opt_len = *p++;
+            p += opt_len;
+            break;
+        } // 转变
+    }     // 尽管
+    return type;
+}
+
+/**
+ *@简短的
+ *
+ *@return int8_t
+ */
+int8_t check_DHCP_leasedIP(void)
+{
+    uint8_t tmp;
+    int32_t ret;
+
+    // WIZchip RCR 值更改为 ARP 超时计数控制
+    tmp = getRCR();
+    setRCR(0x03);
+
+    // IP 冲突检测:ARP 请求 -ARP 回复
+    // 使用 UDP wizchip_sendto() 函数广播 ARP 请求以检查 IP 冲突
+    ret = wizchip_sendto(DHCP_SOCKET, (uint8_t *)"CHECK_IP_CONFLICT", 17, gWIZNETINFO.ip, 5000);
+
+    // Rcr值恢复
+    setRCR(tmp);
+
+    if (ret == SOCKERR_TIMEOUT)
+    {
+        // UDP 发送超时发生:分配的 IP 地址是唯一的,DHCP 成功
+        LOG_D("> Check leased IP - OK");
+        return 1;
+    }
+    else
+    {
+        // 收到 ARP 回复等:发生 IP 地址冲突,DHCP 失败
+        send_DHCP_DECLINE();
+
+        // 等待 1s 结束;等待完成发送 DECLINE 消息;
+        rt_thread_mdelay(1000);
+        return 0;
+    }
+}
+
+/**
+ *@brief 主循环中的 DHCP 客户端
+ *
+ *@return uint8_t
+ */
+uint8_t DHCP_run(uint8_t flag)
+{
+    uint8_t type = 0;
+
+    setSHAR(gWIZNETINFO.mac); // 设置w5500 mac
+
+    RyanW5500Socket *sock = RyanW5500SocketCreate(Sn_MR_UDP, DHCP_CLIENT_PORT);
+    if (NULL == sock)
+    {
+        LOG_W("dhcp socket失败");
+        return -1;
+    }
+
+    uint8_t *dhcpDataBuf = (uint8_t *)rt_malloc(RIP_MSG_SIZE);
+
+    DHCP_SOCKET = sock->socket; // SOCK_DHCP
+    pDHCPMSG = (RIP_MSG *)dhcpDataBuf;
+
+    if (1 != flag) // flag 1表示处于续租状态
+    {
+        // 生成唯一事务id
+        DHCP_XID = 0x12345678;
+        DHCP_XID += gWIZNETINFO.mac[3];
+        DHCP_XID += gWIZNETINFO.mac[4];
+        DHCP_XID += gWIZNETINFO.mac[5];
+        DHCP_XID += (gWIZNETINFO.mac[3] ^ gWIZNETINFO.mac[4] ^ gWIZNETINFO.mac[5]);
+
+        dhcp_state = STATE_DHCP_INIT;
+        platformTimerInit(&dhcp_lease_time);
+    }
+
+    uint8_t dhcp_retry_count = 0;
+    platformTimer_t recvTimer = {0};
+    platformTimerCutdown(&recvTimer, DHCP_WAIT_TIME);
+
+    while (1)
+    {
+        type = parseDHCPMSG();
+
+        switch (dhcp_state)
+        {
+        case STATE_DHCP_INIT: // dhcp初始化状态
+            memset(gWIZNETINFO.ip, 0, sizeof(gWIZNETINFO.ip));
+            send_DHCP_DISCOVER(); // 客户端发送Discover报文
+            dhcp_state = STATE_DHCP_DISCOVER;
+            break;
+
+        case STATE_DHCP_DISCOVER:
+            if (DHCP_OFFER == type) // 服务器提供地址续约,offer报文
+            {
+                LOG_D("> Receive DHCP_OFFER");
+                memcpy(gWIZNETINFO.ip, pDHCPMSG->yiaddr, sizeof(gWIZNETINFO.ip));
+                send_DHCP_REQUEST(); // 发送请求地址租用 request报文
+                dhcp_state = STATE_DHCP_REQUEST;
+            }
+
+            break;
+
+        case STATE_DHCP_REQUEST:  // 客户端选择并请求地址租用
+            if (DHCP_NAK == type) // 服务器取消把地址租用给客户端
+            {
+                LOG_D("> Receive DHCP_NACK");
+                dhcp_state = STATE_DHCP_DISCOVER;
+            }
+
+            else if (DHCP_ACK == type) // 服务器确认将地址租用给客户端 ack报文
+            {
+                LOG_D("> Receive DHCP_ACK");
+                // 发生 IP 地址冲突
+                dhcp_state = check_DHCP_leasedIP() ? STATE_DHCP_LEASED : STATE_DHCP_INIT;
+            }
+
+            break;
+
+        case STATE_DHCP_LEASED: // 当租期超过50%(1/2)时,客户端会以单播形式向DHCP服务器发送DHCP Request报文来续租IP地址。
+            if (dhcp_lease_time.timeOut != 0 && platformTimerRemain(&dhcp_lease_time) < (dhcp_lease_time.timeOut / 2))
+            {
+                LOG_D("> Maintains the IP address ");
+                DHCP_XID++;
+                send_DHCP_REQUEST();
+
+                dhcp_state = STATE_DHCP_REREQUEST;
+            }
+            break;
+
+        case STATE_DHCP_REREQUEST: // 如果收到DHCP服务器发送的DHCP ACK报文,则按相应时间延长IP地址租期。如果没有,还是保持使用该IP地址。
+            if (type == DHCP_ACK)
+            {
+                // 不需要判断续租分配的新ip还是旧ip,都会写入到w5500寄存器里
+                LOG_D("> Receive DHCP_ACK, Maintains the IP address");
+                dhcp_state = STATE_DHCP_LEASED;
+            }
+            else if (type == DHCP_NAK)
+            {
+                LOG_D("> Receive DHCP_NACK, Failed to maintain ip");
+                dhcp_state = STATE_DHCP_DISCOVER;
+            }
+
+            break;
+
+        default:
+            break;
+        }
+
+        if (STATE_DHCP_LEASED == dhcp_state)
+            goto next;
+
+        // 如果超时,根据现有状态进行报文重发尝试
+        if (0 == platformTimerRemain(&recvTimer))
+        {
+            switch (dhcp_state)
+            {
+            case STATE_DHCP_DISCOVER:
+                LOG_D("<<timeout>> state : STATE_DHCP_DISCOVER");
+                send_DHCP_DISCOVER();
+                break;
+
+            case STATE_DHCP_REQUEST:
+                LOG_D("<<timeout>> state : STATE_DHCP_REQUEST");
+                send_DHCP_REQUEST();
+                break;
+
+            case STATE_DHCP_REREQUEST:
+                LOG_D("<<timeout>> state : STATE_DHCP_REREQUEST");
+                send_DHCP_REQUEST();
+                break;
+
+            default:
+                break;
+            }
+
+            platformTimerCutdown(&recvTimer, DHCP_WAIT_TIME);
+            dhcp_retry_count++;
+        }
+
+        if (dhcp_retry_count >= MAX_DHCP_RETRY)
+        {
+            wiz_closesocket(sock->socket);
+            free(dhcpDataBuf);
+            return -1;
+        }
+
+        delay(100);
+    }
+
+next:
+    wiz_closesocket(sock->socket);
+    free(dhcpDataBuf);
+    return 0;
+}
+
+/**
+ *@brief 获取租用总时长 ms
+ *
+ *@return uint32_t
+ */
+uint32_t getDHCPLeaseTime(void)
+{
+    if (NETINFO_DHCP != gWIZNETINFO.dhcp)
+        return 0;
+
+    return dhcp_lease_time.timeOut;
+}
+
+uint32_t getDHCPRemainLeaseTime(void)
+{
+    return platformTimerRemain(&dhcp_lease_time);
+}

+ 40 - 0
ioLibrary/DHCP/wizchip_dhcp.h

@@ -0,0 +1,40 @@
+
+#ifndef _WIZCHIP_DHCP_H_
+#define _WIZCHIP_DHCP_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define MAX_DHCP_RETRY 6    // 最大重试计数
+#define DHCP_WAIT_TIME 3000 // 等待时间
+
+#define DHCP_SERVER_PORT 67 // DHCP 服务器端口号
+#define DHCP_CLIENT_PORT 68 // DHCP 客户端端口号
+
+#define MAGIC_COOKIE 0x63825363 // You should not modify it number.
+
+#define DCHP_HOST_NAME "RyanW5500DHCP\0" // 主机名
+
+    enum
+    {
+        DHCP_FAILED = 0, // 处理失败
+        DHCP_RUNNING,    // 处理 DHCP 协议
+        DHCP_IP_ASSIGN,  // 首先从DHPC服务器占用IP(如果cbfunc ==空,则充当默认default_ip_assign)
+        DHCP_IP_CHANGED, // 通过来自 DHCP 的新 IP 更改 IP 地址(如果 cbfunc == null,则充当默认 default_ip_update)
+        DHCP_IP_LEASED,  // dhcp ip已准备好
+        DHCP_STOPPED     // 停止处理 DHCP 协议
+    };
+
+    uint8_t DHCP_run(uint8_t flag);
+
+    // dhcp租用时间相关
+    uint32_t getDHCPLeaseTime(void);
+    uint32_t getDHCPRemainLeaseTime(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _WIZCHIP_DHCP_H_ */

+ 508 - 0
ioLibrary/DNS/wizchip_dns.c

@@ -0,0 +1,508 @@
+#define DBG_ENABLE
+
+#define DBG_SECTION_NAME ("dns")
+#define DBG_LEVEL DBG_WARNING
+#define DBG_COLOR
+
+#include "RyanW5500Store.h"
+
+#include "wizchip_socket.h"
+#include "wizchip_dns.h"
+
+#define INITRTT 2000L                                       /* Initial smoothed response time */
+#define MAXCNAME (MAX_DOMAIN_NAME + (MAX_DOMAIN_NAME >> 1)) /* Maximum amount of cname recursion */
+
+#define TYPE_A 1      /* Host address */
+#define TYPE_NS 2     /* Name server */
+#define TYPE_MD 3     /* Mail destination (obsolete) */
+#define TYPE_MF 4     /* Mail forwarder (obsolete) */
+#define TYPE_CNAME 5  /* Canonical name */
+#define TYPE_SOA 6    /* Start of Authority */
+#define TYPE_MB 7     /* Mailbox name (experimental) */
+#define TYPE_MG 8     /* Mail group member (experimental) */
+#define TYPE_MR 9     /* Mail rename name (experimental) */
+#define TYPE_NULL 10  /* Null (experimental) */
+#define TYPE_WKS 11   /* Well-known sockets */
+#define TYPE_PTR 12   /* Pointer record */
+#define TYPE_HINFO 13 /* Host information */
+#define TYPE_MINFO 14 /* Mailbox information (experimental)*/
+#define TYPE_MX 15    /* Mail exchanger */
+#define TYPE_TXT 16   /* Text strings */
+#define TYPE_ANY 255  /* Matches any type */
+
+#define CLASS_IN 1 /* The ARPA Internet */
+
+/* Round trip timing parameters */
+#define AGAIN 8  /* Average RTT gain = 1/8 */
+#define LAGAIN 3 /* Log2(AGAIN) */
+#define DGAIN 4  /* Mean deviation gain = 1/4 */
+#define LDGAIN 2 /* log2(DGAIN) */
+
+/* Header for all domain messages */
+struct dhdr
+{
+    uint16_t id; /* Identification */
+    uint8_t qr;  /* Query/Response */
+#define QUERY 0
+#define RESPONSE 1
+    uint8_t opcode;
+#define IQUERY 1
+    uint8_t aa;    /* Authoratative answer */
+    uint8_t tc;    /* Truncation */
+    uint8_t rd;    /* Recursion desired */
+    uint8_t ra;    /* Recursion available */
+    uint8_t rcode; /* Response code */
+#define NO_ERROR 0
+#define FORMAT_ERROR 1
+#define SERVER_FAIL 2
+#define NAME_ERROR 3
+#define NOT_IMPL 4
+#define REFUSED 5
+    uint16_t qdcount; /* Question count */
+    uint16_t ancount; /* Answer count */
+    uint16_t nscount; /* Authority (name server) count */
+    uint16_t arcount; /* Additional record count */
+};
+
+uint8_t *pDNSMSG;   // DNS message buffer
+uint8_t DNS_SOCKET; // SOCKET number for DNS
+uint16_t DNS_MSGID; // DNS message ID
+
+/* converts uint16_t from network buffer to a host byte order integer. */
+uint16_t get16(uint8_t *s)
+{
+    uint16_t i;
+    i = *s++ << 8;
+    i = i + *s;
+    return i;
+}
+
+/* copies uint16_t to the network buffer with network byte order. */
+uint8_t *put16(uint8_t *s, uint16_t i)
+{
+    *s++ = i >> 8;
+    *s++ = i;
+    return s;
+}
+
+/*
+ *              CONVERT A DOMAIN NAME TO THE HUMAN-READABLE FORM
+ *
+ * Description : This function converts a compressed domain name to the human-readable form
+ * Arguments   : msg        - is a pointer to the reply message
+ *               compressed - is a pointer to the domain name in reply message.
+ *               buf        - is a pointer to the buffer for the human-readable form name.
+ *               len        - is the MAX. size of buffer.
+ * Returns     : the length of compressed message
+ */
+int parse_name(uint8_t *msg, uint8_t *compressed, char *buf, int16_t len)
+{
+    uint16_t slen; /* Length of current segment */
+    uint8_t *cp;
+    int clen = 0;     /* Total length of compressed name */
+    int indirect = 0; /* Set if indirection encountered */
+    int nseg = 0;     /* Total number of segments in name */
+
+    cp = compressed;
+
+    for (;;)
+    {
+        slen = *cp++; /* Length of this segment */
+
+        if (!indirect)
+            clen++;
+
+        if ((slen & 0xc0) == 0xc0)
+        {
+            if (!indirect)
+                clen++;
+            indirect = 1;
+            /* Follow indirection */
+            cp = &msg[((slen & 0x3f) << 8) + *cp];
+            slen = *cp++;
+        }
+
+        if (slen == 0) /* zero length == all done */
+            break;
+
+        len -= slen + 1;
+
+        if (len < 0)
+            return -1;
+
+        if (!indirect)
+            clen += slen;
+
+        while (slen-- != 0)
+            *buf++ = (char)*cp++;
+        *buf++ = '.';
+        nseg++;
+    }
+
+    if (nseg == 0)
+    {
+        /* Root name; represent as single dot */
+        *buf++ = '.';
+        len--;
+    }
+
+    *buf++ = '\0';
+    len--;
+
+    return clen; /* Length of compressed message */
+}
+
+/*
+ *              PARSE QUESTION SECTION
+ *
+ * Description : This function parses the qeustion record of the reply message.
+ * Arguments   : msg - is a pointer to the reply message
+ *               cp  - is a pointer to the qeustion record.
+ * Returns     : a pointer the to next record.
+ */
+uint8_t *dns_question(uint8_t *msg, uint8_t *cp)
+{
+    int len;
+    char name[MAXCNAME];
+
+    len = parse_name(msg, cp, name, MAXCNAME);
+
+    if (len == -1)
+        return 0;
+
+    cp += len;
+    cp += 2; /* type */
+    cp += 2; /* class */
+
+    return cp;
+}
+
+/*
+ *              PARSE ANSER SECTION
+ *
+ * Description : This function parses the answer record of the reply message.
+ * Arguments   : msg - is a pointer to the reply message
+ *               cp  - is a pointer to the answer record.
+ * Returns     : a pointer the to next record.
+ */
+uint8_t *dns_answer(uint8_t *msg, uint8_t *cp, uint8_t *ip_from_dns)
+{
+    int len, type;
+    char name[MAXCNAME];
+
+    len = parse_name(msg, cp, name, MAXCNAME);
+
+    if (len == -1)
+        return 0;
+
+    cp += len;
+    type = get16(cp);
+    cp += 2; /* type */
+    cp += 2; /* class */
+    cp += 4; /* ttl */
+    cp += 2; /* len */
+
+    switch (type)
+    {
+    case TYPE_A:
+        /* Just read the address directly into the structure */
+        ip_from_dns[0] = *cp++;
+        ip_from_dns[1] = *cp++;
+        ip_from_dns[2] = *cp++;
+        ip_from_dns[3] = *cp++;
+        break;
+    case TYPE_CNAME:
+    case TYPE_MB:
+    case TYPE_MG:
+    case TYPE_MR:
+    case TYPE_NS:
+    case TYPE_PTR:
+        /* These types all consist of a single domain name */
+        /* convert it to ascii format */
+        len = parse_name(msg, cp, name, MAXCNAME);
+        if (len == -1)
+            return 0;
+
+        cp += len;
+        break;
+    case TYPE_HINFO:
+        len = *cp++;
+        cp += len;
+
+        len = *cp++;
+        cp += len;
+        break;
+    case TYPE_MX:
+        cp += 2;
+        /* Get domain name of exchanger */
+        len = parse_name(msg, cp, name, MAXCNAME);
+        if (len == -1)
+            return 0;
+
+        cp += len;
+        break;
+    case TYPE_SOA:
+        /* Get domain name of name server */
+        len = parse_name(msg, cp, name, MAXCNAME);
+        if (len == -1)
+            return 0;
+
+        cp += len;
+
+        /* Get domain name of responsible person */
+        len = parse_name(msg, cp, name, MAXCNAME);
+        if (len == -1)
+            return 0;
+
+        cp += len;
+
+        cp += 4;
+        cp += 4;
+        cp += 4;
+        cp += 4;
+        cp += 4;
+        break;
+    case TYPE_TXT:
+        /* Just stash */
+        break;
+    default:
+        /* Ignore */
+        break;
+    }
+
+    return cp;
+}
+
+/*
+ *              PARSE THE DNS REPLY
+ *
+ * Description : This function parses the reply message from DNS server.
+ * Arguments   : dhdr - is a pointer to the header for DNS message
+ *               buf  - is a pointer to the reply message.
+ *               len  - is the size of reply message.
+ * Returns     : -1 - Domain name lenght is too big
+ *                0 - Fail (Timout or parse error)
+ *                1 - Success,
+ */
+int8_t parseDNSMSG(struct dhdr *pdhdr, uint8_t *pbuf, uint8_t *ip_from_dns)
+{
+    uint16_t tmp;
+    uint16_t i;
+    uint8_t *msg;
+    uint8_t *cp;
+
+    msg = pbuf;
+    memset(pdhdr, 0, sizeof(*pdhdr));
+
+    pdhdr->id = get16(&msg[0]);
+    tmp = get16(&msg[2]);
+    if (tmp & 0x8000)
+        pdhdr->qr = 1;
+
+    pdhdr->opcode = (tmp >> 11) & 0xf;
+
+    if (tmp & 0x0400)
+        pdhdr->aa = 1;
+    if (tmp & 0x0200)
+        pdhdr->tc = 1;
+    if (tmp & 0x0100)
+        pdhdr->rd = 1;
+    if (tmp & 0x0080)
+        pdhdr->ra = 1;
+
+    pdhdr->rcode = tmp & 0xf;
+    pdhdr->qdcount = get16(&msg[4]);
+    pdhdr->ancount = get16(&msg[6]);
+    pdhdr->nscount = get16(&msg[8]);
+    pdhdr->arcount = get16(&msg[10]);
+
+    /* Now parse the variable length sections */
+    cp = &msg[12];
+
+    /* Question section */
+    for (i = 0; i < pdhdr->qdcount; i++)
+    {
+        cp = dns_question(msg, cp);
+
+        if (!cp)
+            return -1;
+    }
+
+    /* Answer section */
+    for (i = 0; i < pdhdr->ancount; i++)
+    {
+        cp = dns_answer(msg, cp, ip_from_dns);
+
+        if (!cp)
+            return -1;
+    }
+
+    /* Name server (authority) section */
+    for (i = 0; i < pdhdr->nscount; i++)
+    {
+        ;
+    }
+
+    /* Additional section */
+    for (i = 0; i < pdhdr->arcount; i++)
+    {
+        ;
+    }
+
+    if (pdhdr->rcode == 0)
+        return 1; // No error
+    else
+        return 0;
+}
+
+/*
+ *              MAKE DNS QUERY MESSAGE
+ *
+ * Description : This function makes DNS query message.
+ * Arguments   : op   - Recursion desired
+ *               name - is a pointer to the domain name.
+ *               buf  - is a pointer to the buffer for DNS message.
+ *               len  - is the MAX. size of buffer.
+ * Returns     : the pointer to the DNS message.
+ */
+int16_t dns_makequery(uint16_t op, char *name, uint8_t *buf, uint16_t len)
+{
+    uint8_t *cp;
+    char *cp1;
+    char sname[MAXCNAME];
+    char *dname;
+    uint16_t p;
+    uint16_t dlen;
+
+    cp = buf;
+
+    DNS_MSGID++;
+    cp = put16(cp, DNS_MSGID);
+    p = (op << 11) | 0x0100; /* Recursion desired */
+    cp = put16(cp, p);
+    cp = put16(cp, 1);
+    cp = put16(cp, 0);
+    cp = put16(cp, 0);
+    cp = put16(cp, 0);
+
+    strcpy(sname, name);
+    dname = sname;
+    dlen = strlen(dname);
+    for (;;)
+    {
+        /* Look for next dot */
+        cp1 = strchr(dname, '.');
+
+        if (cp1 != NULL)
+            len = cp1 - dname; /* More to come */
+        else
+            len = dlen; /* Last component */
+
+        *cp++ = len; /* Write length of component */
+        if (len == 0)
+            break;
+
+        /* Copy component up to (but not including) dot */
+        strncpy((char *)cp, dname, len);
+        cp += len;
+        if (cp1 == NULL)
+        {
+            *cp++ = 0; /* Last one; write null and finish */
+            break;
+        }
+        dname += len + 1;
+        dlen -= len + 1;
+    }
+
+    cp = put16(cp, 0x0001); /* type */
+    cp = put16(cp, 0x0001); /* class */
+
+    return ((int16_t)((uint32_t)(cp) - (uint32_t)(buf)));
+}
+
+/**
+ * @brief DNS 进程初始化
+ *
+ * @param s 套接字
+ * @param buf 消息的缓冲区
+ */
+// void DNS_init(uint8_t s, uint8_t *buf)
+// {
+
+//     DNS_SOCKET = s; // SOCK_DNS
+//     pDNSMSG = buf;  // User's shared buffer
+//     DNS_MSGID = DNS_MSG_ID;
+// }
+
+/**
+ * @brief 发送DNS查询并接收DNS响应
+ *
+ * @param dns_ip DNS 服务器 IP
+ * @param name 待查询域名
+ * @param ip_from_dns 来自 DNS 服务器的 IP 地址
+ * @return int8_t
+ */
+int8_t DNS_run(uint8_t *dns_ip, uint8_t *name, uint8_t *ip_from_dns, uint8_t *buf)
+{
+    int8_t ret;
+    struct dhdr dhp;
+    uint8_t ip[4];
+    uint8_t retry_count = 0;
+    uint16_t len, port;
+
+    platformTimer_t recvTimer = {0};
+
+    RyanW5500Socket *sock = RyanW5500SocketCreate(SOCK_DGRAM, IPPORT_DOMAIN);
+    if (NULL == sock)
+    {
+        LOG_W("dns socket失败");
+        return -2;
+    }
+
+    LOG_D("> DNS Query to DNS Server : %d.%d.%d.%d", dns_ip[0], dns_ip[1], dns_ip[2], dns_ip[3]);
+
+    DNS_SOCKET = sock->socket; // SOCK_DNS
+    pDNSMSG = buf;             // User's shared buffer
+    DNS_MSGID = DNS_MSG_ID;
+
+    len = dns_makequery(0, (char *)name, pDNSMSG, MAX_DNS_BUF_SIZE);
+    wizchip_sendto(DNS_SOCKET, pDNSMSG, len, dns_ip, IPPORT_DOMAIN);
+
+    platformTimerCutdown(&recvTimer, DNS_WAIT_TIME);
+
+    while (1)
+    {
+        if ((len = getSn_RX_RSR(DNS_SOCKET)) > 0)
+        {
+            if (len > MAX_DNS_BUF_SIZE)
+                len = MAX_DNS_BUF_SIZE;
+            len = wizchip_recvfrom(DNS_SOCKET, pDNSMSG, len, ip, &port);
+            LOG_D("> Receive DNS message from %d.%d.%d.%d(%d). len = %d", ip[0], ip[1], ip[2], ip[3], port, len);
+            ret = parseDNSMSG(&dhp, pDNSMSG, ip_from_dns);
+            break;
+        }
+
+        if (0 == platformTimerRemain(&recvTimer))
+        {
+            LOG_D("> DNS Timeout\r\n");
+            wizchip_sendto(DNS_SOCKET, pDNSMSG, len, dns_ip, IPPORT_DOMAIN);
+            platformTimerCutdown(&recvTimer, DNS_WAIT_TIME);
+            retry_count++;
+        }
+
+        if (retry_count >= MAX_DNS_RETRY)
+        {
+            LOG_D("> DNS Server is not responding : %d.%d.%d.%d", dns_ip[0], dns_ip[1], dns_ip[2], dns_ip[3]);
+            wizchip_close(DNS_SOCKET);
+            return 0; // timeout occurred
+        }
+
+        delay(3);
+    }
+
+    wiz_closesocket(DNS_SOCKET);
+
+    // Return value
+    // 0 > :  failed / 1 - success
+    return ret;
+}

+ 25 - 0
ioLibrary/DNS/wizchip_dns.h

@@ -0,0 +1,25 @@
+
+#ifndef _DNS_H_
+#define _DNS_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+
+#define MAX_DNS_BUF_SIZE 256 // DNS 缓冲区的最大长度
+#define MAX_DOMAIN_NAME 128  // 查询域名的最大长度 例如 "www.google.com"
+#define MAX_DNS_RETRY 2      // 重试次数
+#define DNS_WAIT_TIME 3000   // 等待响应时间,单位 ms。
+#define IPPORT_DOMAIN 53     // DNS 服务器端口号
+#define DNS_MSG_ID 0x1122    // DNS 消息的 ID。你可以修改它任何数字
+
+    extern int8_t DNS_run(uint8_t *dns_ip, uint8_t *name, uint8_t *ip_from_dns, uint8_t *buf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DNS_H_ */

+ 266 - 0
ioLibrary/W5500/w5500.c

@@ -0,0 +1,266 @@
+//*****************************************************************************
+//
+//! \file w5500.c
+//! \brief W5500 HAL Interface.
+//! \version 1.0.2
+//! \date 2013/10/21
+//! \par  Revision history
+//!       <2015/02/05> Notice
+//!        The version history is not updated after this point.
+//!        Download the latest version directly from GitHub. Please visit the our GitHub repository for ioLibrary.
+//!        >> https://github.com/Wiznet/ioLibrary_Driver
+//!       <2014/05/01> V1.0.2
+//!         1. Implicit type casting -> Explicit type casting. Refer to M20140501
+//!            Fixed the problem on porting into under 32bit MCU
+//!            Issued by Mathias ClauBen, wizwiki forum ID Think01 and bobh
+//!            Thank for your interesting and serious advices.
+//!       <2013/12/20> V1.0.1
+//!         1. Remove warning
+//!         2. WIZCHIP_READ_BUF WIZCHIP_WRITE_BUF in case _WIZCHIP_IO_MODE_SPI_FDM_
+//!            for loop optimized(removed). refer to M20131220
+//!       <2013/10/21> 1st Release
+//! \author MidnightCow
+//! \copyright
+//!
+//! Copyright (c)  2013, WIZnet Co., LTD.
+//! All rights reserved.
+//!
+//! Redistribution and use in source and binary forms, with or without
+//! modification, are permitted provided that the following conditions
+//! are met:
+//!
+//!     * Redistributions of source code must retain the above copyright
+//! notice, this list of conditions and the following disclaimer.
+//!     * Redistributions in binary form must reproduce the above copyright
+//! notice, this list of conditions and the following disclaimer in the
+//! documentation and/or other materials provided with the distribution.
+//!     * Neither the name of the <ORGANIZATION> nor the names of its
+//! contributors may be used to endorse or promote products derived
+//! from this software without specific prior written permission.
+//!
+//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+//! THE POSSIBILITY OF SUCH DAMAGE.
+//
+//*****************************************************************************
+// #include <stdio.h>
+#include "w5500.h"
+
+#define _W5500_SPI_VDM_OP_ 0x00
+#define _W5500_SPI_FDM_OP_LEN1_ 0x01
+#define _W5500_SPI_FDM_OP_LEN2_ 0x02
+#define _W5500_SPI_FDM_OP_LEN4_ 0x03
+
+#if (_WIZCHIP_ == 5500)
+////////////////////////////////////////////////////
+
+uint8_t WIZCHIP_READ(uint32_t AddrSel)
+{
+    uint8_t ret;
+    uint8_t spi_data[3];
+
+    WIZCHIP_CRITICAL_ENTER();
+    WIZCHIP.CS._select();
+
+    AddrSel |= (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_);
+
+    if (!WIZCHIP.IF.SPI._read_burst || !WIZCHIP.IF.SPI._write_burst) // byte operation
+    {
+        WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16);
+        WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8);
+        WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0);
+    }
+    else // burst operation
+    {
+        spi_data[0] = (AddrSel & 0x00FF0000) >> 16;
+        spi_data[1] = (AddrSel & 0x0000FF00) >> 8;
+        spi_data[2] = (AddrSel & 0x000000FF) >> 0;
+        WIZCHIP.IF.SPI._write_burst(spi_data, 3);
+    }
+    ret = WIZCHIP.IF.SPI._read_byte();
+
+    WIZCHIP.CS._deselect();
+    WIZCHIP_CRITICAL_EXIT();
+    return ret;
+}
+
+void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb)
+{
+    uint8_t spi_data[4];
+
+    WIZCHIP_CRITICAL_ENTER();
+    WIZCHIP.CS._select();
+
+    AddrSel |= (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_);
+
+    // if(!WIZCHIP.IF.SPI._read_burst || !WIZCHIP.IF.SPI._write_burst) 	// byte operation
+    if (!WIZCHIP.IF.SPI._write_burst) // byte operation
+    {
+        WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16);
+        WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8);
+        WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0);
+        WIZCHIP.IF.SPI._write_byte(wb);
+    }
+    else // burst operation
+    {
+        spi_data[0] = (AddrSel & 0x00FF0000) >> 16;
+        spi_data[1] = (AddrSel & 0x0000FF00) >> 8;
+        spi_data[2] = (AddrSel & 0x000000FF) >> 0;
+        spi_data[3] = wb;
+        WIZCHIP.IF.SPI._write_burst(spi_data, 4);
+    }
+
+    WIZCHIP.CS._deselect();
+    WIZCHIP_CRITICAL_EXIT();
+}
+
+void WIZCHIP_READ_BUF(uint32_t AddrSel, uint8_t *pBuf, uint16_t len)
+{
+    uint8_t spi_data[3];
+    uint16_t i;
+
+    WIZCHIP_CRITICAL_ENTER();
+    WIZCHIP.CS._select();
+
+    AddrSel |= (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_);
+
+    if (!WIZCHIP.IF.SPI._read_burst || !WIZCHIP.IF.SPI._write_burst) // byte operation
+    {
+        WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16);
+        WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8);
+        WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0);
+        for (i = 0; i < len; i++)
+            pBuf[i] = WIZCHIP.IF.SPI._read_byte();
+    }
+    else // burst operation
+    {
+        spi_data[0] = (AddrSel & 0x00FF0000) >> 16;
+        spi_data[1] = (AddrSel & 0x0000FF00) >> 8;
+        spi_data[2] = (AddrSel & 0x000000FF) >> 0;
+        WIZCHIP.IF.SPI._write_burst(spi_data, 3);
+        WIZCHIP.IF.SPI._read_burst(pBuf, len);
+    }
+
+    WIZCHIP.CS._deselect();
+    WIZCHIP_CRITICAL_EXIT();
+}
+
+void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t *pBuf, uint16_t len)
+{
+    uint8_t spi_data[3];
+    uint16_t i;
+
+    WIZCHIP_CRITICAL_ENTER();
+    WIZCHIP.CS._select();
+
+    AddrSel |= (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_);
+
+    if (!WIZCHIP.IF.SPI._write_burst) // byte operation
+    {
+        WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16);
+        WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8);
+        WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0);
+        for (i = 0; i < len; i++)
+            WIZCHIP.IF.SPI._write_byte(pBuf[i]);
+    }
+    else // burst operation
+    {
+        spi_data[0] = (AddrSel & 0x00FF0000) >> 16;
+        spi_data[1] = (AddrSel & 0x0000FF00) >> 8;
+        spi_data[2] = (AddrSel & 0x000000FF) >> 0;
+        WIZCHIP.IF.SPI._write_burst(spi_data, 3);
+        WIZCHIP.IF.SPI._write_burst(pBuf, len);
+    }
+
+    WIZCHIP.CS._deselect();
+    WIZCHIP_CRITICAL_EXIT();
+}
+
+uint16_t getSn_TX_FSR(uint8_t sn)
+{
+    uint16_t val = 0, val1 = 0;
+
+    do
+    {
+        val1 = WIZCHIP_READ(Sn_TX_FSR(sn));
+        val1 = (val1 << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn), 1));
+        if (val1 != 0)
+        {
+            val = WIZCHIP_READ(Sn_TX_FSR(sn));
+            val = (val << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn), 1));
+        }
+    } while (val != val1);
+    return val;
+}
+
+uint16_t getSn_RX_RSR(uint8_t sn)
+{
+    uint16_t val = 0, val1 = 0;
+
+    do
+    {
+        val1 = WIZCHIP_READ(Sn_RX_RSR(sn));
+        val1 = (val1 << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn), 1));
+        if (val1 != 0)
+        {
+            val = WIZCHIP_READ(Sn_RX_RSR(sn));
+            val = (val << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn), 1));
+        }
+    } while (val != val1);
+    return val;
+}
+
+void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len)
+{
+    uint16_t ptr = 0;
+    uint32_t addrsel = 0;
+
+    if (len == 0)
+        return;
+    ptr = getSn_TX_WR(sn);
+    // M20140501 : implict type casting -> explict type casting
+    // addrsel = (ptr << 8) + (WIZCHIP_TXBUF_BLOCK(sn) << 3);
+    addrsel = ((uint32_t)ptr << 8) + (WIZCHIP_TXBUF_BLOCK(sn) << 3);
+    //
+    WIZCHIP_WRITE_BUF(addrsel, wizdata, len);
+
+    ptr += len;
+    setSn_TX_WR(sn, ptr);
+}
+
+void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len)
+{
+    uint16_t ptr = 0;
+    uint32_t addrsel = 0;
+
+    if (len == 0)
+        return;
+    ptr = getSn_RX_RD(sn);
+    // M20140501 : implict type casting -> explict type casting
+    // addrsel = ((ptr << 8) + (WIZCHIP_RXBUF_BLOCK(sn) << 3);
+    addrsel = ((uint32_t)ptr << 8) + (WIZCHIP_RXBUF_BLOCK(sn) << 3);
+    //
+    WIZCHIP_READ_BUF(addrsel, wizdata, len);
+    ptr += len;
+
+    setSn_RX_RD(sn, ptr);
+}
+
+void wiz_recv_ignore(uint8_t sn, uint16_t len)
+{
+    uint16_t ptr = 0;
+
+    ptr = getSn_RX_RD(sn);
+    ptr += len;
+    setSn_RX_RD(sn, ptr);
+}
+
+#endif

+ 2150 - 0
ioLibrary/W5500/w5500.h

@@ -0,0 +1,2150 @@
+//*****************************************************************************
+//
+//! \file w5500.h
+//! \brief W5500 HAL Header File.
+//! \version 1.0.0
+//! \date 2013/10/21
+//! \par  Revision history
+//!       <2015/02/05> Notice
+//!        The version history is not updated after this point.
+//!        Download the latest version directly from GitHub. Please visit the our GitHub repository for ioLibrary.
+//!        >> https://github.com/Wiznet/ioLibrary_Driver
+//!       <2013/10/21> 1st Release
+//! \author MidnightCow
+//! \copyright
+//!
+//! Copyright (c)  2013, WIZnet Co., LTD.
+//! All rights reserved.
+//!
+//! Redistribution and use in source and binary forms, with or without
+//! modification, are permitted provided that the following conditions
+//! are met:
+//!
+//!     * Redistributions of source code must retain the above copyright
+//! notice, this list of conditions and the following disclaimer.
+//!     * Redistributions in binary form must reproduce the above copyright
+//! notice, this list of conditions and the following disclaimer in the
+//! documentation and/or other materials provided with the distribution.
+//!     * Neither the name of the <ORGANIZATION> nor the names of its
+//! contributors may be used to endorse or promote products derived
+//! from this software without specific prior written permission.
+//!
+//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+//! THE POSSIBILITY OF SUCH DAMAGE.
+//
+//*****************************************************************************
+
+//
+
+#ifndef _W5500_H_
+#define _W5500_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+#include "wizchip_conf.h"
+
+/// @cond DOXY_APPLY_CODE
+#if (_WIZCHIP_ == 5500)
+    /// @endcond
+
+#define _W5500_IO_BASE_ 0x00000000
+
+#define _W5500_SPI_READ_ (0x00 << 2)  //< SPI interface Read operation in Control Phase
+#define _W5500_SPI_WRITE_ (0x01 << 2) //< SPI interface Write operation in Control Phase
+
+#define WIZCHIP_CREG_BLOCK 0x00            //< Common register block
+#define WIZCHIP_SREG_BLOCK(N) (1 + 4 * N)  //< Socket N register block
+#define WIZCHIP_TXBUF_BLOCK(N) (2 + 4 * N) //< Socket N Tx buffer address block
+#define WIZCHIP_RXBUF_BLOCK(N) (3 + 4 * N) //< Socket N Rx buffer address block
+
+#define WIZCHIP_OFFSET_INC(ADDR, N) (ADDR + (N << 8)) //< Increase offset address
+
+///////////////////////////////////////
+// Definition For Legacy Chip Driver //
+///////////////////////////////////////
+#define IINCHIP_READ(ADDR) WIZCHIP_READ(ADDR)                             ///< The defined for legacy chip driver
+#define IINCHIP_WRITE(ADDR, VAL) WIZCHIP_WRITE(ADDR, VAL)                 ///< The defined for legacy chip driver
+#define IINCHIP_READ_BUF(ADDR, BUF, LEN) WIZCHIP_READ_BUF(ADDR, BUF, LEN) ///< The defined for legacy chip driver
+#define IINCHIP_WRITE_BUF(ADDR, BUF, LEN) WIZCHIP_WRITE(ADDR, BUF, LEN)   ///< The defined for legacy chip driver
+
+    //////////////////////////////
+    //--------------------------  defgroup ---------------------------------
+    /**
+     * @defgroup W5500 W5500
+     *
+     * @brief WHIZCHIP register defines and I/O functions of @b W5500.
+     *
+     * - @ref WIZCHIP_register : @ref Common_register_group and @ref Socket_register_group
+     * - @ref WIZCHIP_IO_Functions : @ref Basic_IO_function, @ref Common_register_access_function and @ref Socket_register_access_function
+     */
+
+    /**
+     * @defgroup WIZCHIP_register WIZCHIP register
+     * @ingroup W5500
+     *
+     * @brief WHIZCHIP register defines register group of @b W5500.
+     *
+     * - @ref Common_register_group : Common register group
+     * - @ref Socket_register_group : \c SOCKET n register group
+     */
+
+    /**
+     * @defgroup WIZCHIP_IO_Functions WIZCHIP I/O functions
+     * @ingroup W5500
+     *
+     * @brief This supports the basic I/O functions for @ref WIZCHIP_register.
+     *
+     * - <b> Basic I/O function </b> \n
+     *   WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF() \n\n
+     *
+     * - @ref Common_register_group <b>access functions</b> \n
+     * 	-# @b Mode \n
+     *    getMR(), setMR()
+     * 	-# @b Interrupt \n
+     *    getIR(), setIR(), getIMR(), setIMR(), getSIR(), setSIR(), getSIMR(), setSIMR(), getINTLEVEL(), setINTLEVEL()
+     * 	-# <b> Network Information </b> \n
+     *    getSHAR(), setSHAR(), getGAR(), setGAR(), getSUBR(), setSUBR(), getSIPR(), setSIPR()
+     * 	-# @b Retransmission \n
+     *    getRCR(), setRCR(), getRTR(), setRTR()
+     * 	-# @b PPPoE \n
+     *    getPTIMER(), setPTIMER(), getPMAGIC(), getPMAGIC(), getPSID(), setPSID(), getPHAR(), setPHAR(), getPMRU(), setPMRU()
+     * 	-# <b> ICMP packet </b>\n
+     *    getUIPR(), getUPORTR()
+     * 	-# @b etc. \n
+     *    getPHYCFGR(), setPHYCFGR(), getVERSIONR() \n\n
+     *
+     * - \ref Socket_register_group <b>access functions</b> \n
+     *   -# <b> SOCKET control</b> \n
+     *      getSn_MR(), setSn_MR(), getSn_CR(), setSn_CR(), getSn_IMR(), setSn_IMR(), getSn_IR(), setSn_IR()
+     *   -# <b> SOCKET information</b> \n
+     *      getSn_SR(), getSn_DHAR(), setSn_DHAR(), getSn_PORT(), setSn_PORT(), getSn_DIPR(), setSn_DIPR(), getSn_DPORT(), setSn_DPORT()
+     *      getSn_MSSR(), setSn_MSSR()
+     *   -# <b> SOCKET communication </b> \n
+     *      getSn_RXBUF_SIZE(), setSn_RXBUF_SIZE(), getSn_TXBUF_SIZE(), setSn_TXBUF_SIZE() \n
+     *      getSn_TX_RD(), getSn_TX_WR(), setSn_TX_WR() \n
+     *      getSn_RX_RD(), setSn_RX_RD(), getSn_RX_WR() \n
+     *      getSn_TX_FSR(), getSn_RX_RSR(), getSn_KPALVTR(), setSn_KPALVTR()
+     *   -# <b> IP header field </b> \n
+     *      getSn_FRAG(), setSn_FRAG(),  getSn_TOS(), setSn_TOS() \n
+     *      getSn_TTL(), setSn_TTL()
+     */
+
+    /**
+     * @defgroup Common_register_group Common register
+     * @ingroup WIZCHIP_register
+     *
+     * @brief Common register group\n
+     * It set the basic for the networking\n
+     * It set the configuration such as interrupt, network information, ICMP, etc.
+     * @details
+     * @sa MR : Mode register.
+     * @sa GAR, SUBR, SHAR, SIPR
+     * @sa INTLEVEL, IR, IMR, SIR, SIMR : Interrupt.
+     * @sa _RTR_, _RCR_ : Data retransmission.
+     * @sa PTIMER, PMAGIC, PHAR, PSID, PMRU : PPPoE.
+     * @sa UIPR, UPORTR : ICMP message.
+     * @sa PHYCFGR, VERSIONR : etc.
+     */
+
+    /**
+     * @defgroup Socket_register_group Socket register
+     * @ingroup WIZCHIP_register
+     *
+     * @brief Socket register group.\n
+     * Socket register configures and control SOCKETn which is necessary to data communication.
+     * @details
+     * @sa Sn_MR, Sn_CR, Sn_IR, Sn_IMR : SOCKETn Control
+     * @sa Sn_SR, Sn_PORT, Sn_DHAR, Sn_DIPR, Sn_DPORT : SOCKETn Information
+     * @sa Sn_MSSR, Sn_TOS, Sn_TTL, Sn_KPALVTR, Sn_FRAG : Internet protocol.
+     * @sa Sn_RXBUF_SIZE, Sn_TXBUF_SIZE, Sn_TX_FSR, Sn_TX_RD, Sn_TX_WR, Sn_RX_RSR, Sn_RX_RD, Sn_RX_WR : Data communication
+     */
+
+    /**
+     * @defgroup Basic_IO_function Basic I/O function
+     * @ingroup WIZCHIP_IO_Functions
+     * @brief These are basic input/output functions to read values from register or write values to register.
+     */
+
+/**
+ * @defgroup Common_register_access_function Common register access functions
+ * @ingroup WIZCHIP_IO_Functions
+ * @brief These are functions to access <b>common registers</b>.
+ */
+
+/**
+ * @defgroup Socket_register_access_function Socket register access functions
+ * @ingroup WIZCHIP_IO_Functions
+ * @brief These are functions to access <b>socket registers</b>.
+ */
+
+//------------------------------- defgroup end --------------------------------------------
+//----------------------------- W5500 Common Registers IOMAP -----------------------------
+/**
+ * @ingroup Common_register_group
+ * @brief Mode Register address(R/W)\n
+ * @ref MR is used for S/W reset, ping block mode, PPPoE mode and etc.
+ * @details Each bit of @ref MR defined as follows.
+ * <table>
+ * 		<tr>  <td>7</td> <td>6</td> <td>5</td> <td>4</td> <td>3</td> <td>2</td> <td>1</td> <td>0</td>   </tr>
+ * 		<tr>  <td>RST</td> <td>Reserved</td> <td>WOL</td> <td>PB</td> <td>PPPoE</td> <td>Reserved</td> <td>FARP</td> <td>Reserved</td> </tr>
+ * </table>
+ * - \ref MR_RST		 	: Reset
+ * - \ref MR_WOL       	: Wake on LAN
+ * - \ref MR_PB         : Ping block
+ * - \ref MR_PPPOE      : PPPoE mode
+ * - \ref MR_FARP			: Force ARP mode
+ */
+#define MR (_W5500_IO_BASE_ + (0x0000 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief Gateway IP Register address(R/W)
+ * @details @ref GAR configures the default gateway address.
+ */
+#define GAR (_W5500_IO_BASE_ + (0x0001 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief Subnet mask Register address(R/W)
+ * @details @ref SUBR configures the subnet mask address.
+ */
+#define SUBR (_W5500_IO_BASE_ + (0x0005 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief Source MAC Register address(R/W)
+ * @details @ref SHAR configures the source hardware address.
+ */
+#define SHAR (_W5500_IO_BASE_ + (0x0009 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief Source IP Register address(R/W)
+ * @details @ref SIPR configures the source IP address.
+ */
+#define SIPR (_W5500_IO_BASE_ + (0x000F << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief Set Interrupt low level timer register address(R/W)
+ * @details @ref INTLEVEL configures the Interrupt Assert Time.
+ */
+#define INTLEVEL (_W5500_IO_BASE_ + (0x0013 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief Interrupt Register(R/W)
+ * @details @ref IR indicates the interrupt status. Each bit of @ref IR will be still until the bit will be written to by the host.
+ * If @ref IR is not equal to x00 INTn PIN is asserted to low until it is x00\n\n
+ * Each bit of @ref IR defined as follows.
+ * <table>
+ * 		<tr>  <td>7</td> <td>6</td> <td>5</td> <td>4</td> <td>3</td> <td>2</td> <td>1</td> <td>0</td>   </tr>
+ * 		<tr>  <td>CONFLICT</td> <td>UNREACH</td> <td>PPPoE</td> <td>MP</td> <td>Reserved</td> <td>Reserved</td> <td>Reserved</td> <td>Reserved</td> </tr>
+ * </table>
+ * - \ref IR_CONFLICT : IP conflict
+ * - \ref IR_UNREACH  : Destination unreachable
+ * - \ref IR_PPPoE	  : PPPoE connection close
+ * - \ref IR_MP		  : Magic packet
+ */
+#define IR (_W5500_IO_BASE_ + (0x0015 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief Interrupt mask register(R/W)
+ * @details @ref _IMR_ is used to mask interrupts. Each bit of @ref _IMR_ corresponds to each bit of @ref IR.
+ * When a bit of @ref _IMR_ is and the corresponding bit of @ref IR is  an interrupt will be issued. In other words,
+ * if a bit of @ref _IMR_ is  an interrupt will not be issued even if the corresponding bit of @ref IR is \n\n
+ * Each bit of @ref _IMR_ defined as the following.
+ * <table>
+ * 		<tr>  <td>7</td> <td>6</td> <td>5</td> <td>4</td> <td>3</td> <td>2</td> <td>1</td> <td>0</td>   </tr>
+ * 		<tr>  <td>IM_IR7</td> <td>IM_IR6</td> <td>IM_IR5</td> <td>IM_IR4</td> <td>Reserved</td> <td>Reserved</td> <td>Reserved</td> <td>Reserved</td> </tr>
+ * </table>
+ * - \ref IM_IR7 : IP Conflict Interrupt Mask
+ * - \ref IM_IR6 : Destination unreachable Interrupt Mask
+ * - \ref IM_IR5 : PPPoE Close Interrupt Mask
+ * - \ref IM_IR4 : Magic Packet Interrupt Mask
+ */
+// M20150401 : Rename SYMBOE ( Re-define error in a compile)
+// #define IMR                (_W5500_IO_BASE_ + (0x0016 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+#define _IMR_ (_W5500_IO_BASE_ + (0x0016 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief Socket Interrupt Register(R/W)
+ * @details @ref SIR indicates the interrupt status of Socket.\n
+ * Each bit of @ref SIR be still until @ref Sn_IR is cleared by the host.\n
+ * If @ref Sn_IR is not equal to x00 the n-th bit of @ref SIR is and INTn PIN is asserted until @ref SIR is x00 */
+#define SIR (_W5500_IO_BASE_ + (0x0017 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief Socket Interrupt Mask Register(R/W)
+ * @details Each bit of @ref SIMR corresponds to each bit of @ref SIR.
+ * When a bit of @ref SIMR is and the corresponding bit of @ref SIR is  Interrupt will be issued.
+ * In other words, if a bit of @ref SIMR is  an interrupt will be not issued even if the corresponding bit of @ref SIR is
+ */
+#define SIMR (_W5500_IO_BASE_ + (0x0018 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief Timeout register address( 1 is 100us )(R/W)
+ * @details @ref _RTR_ configures the retransmission timeout period. The unit of timeout period is 100us and the default of @ref _RTR_ is x07D0.
+ * And so the default timeout period is 200ms(100us X 2000). During the time configured by @ref _RTR_, W5500 waits for the peer response
+ * to the packet that is transmitted by \ref Sn_CR (CONNECT, DISCON, CLOSE, SEND, SEND_MAC, SEND_KEEP command).
+ * If the peer does not respond within the @ref _RTR_ time, W5500 retransmits the packet or issues timeout.
+ */
+// M20150401 : Rename SYMBOE ( Re-define error in a compile)
+// #define RTR                (_W5500_IO_BASE_ + (0x0019 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+#define _RTR_ (_W5500_IO_BASE_ + (0x0019 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief Retry count register(R/W)
+ * @details @ref _RCR_ configures the number of time of retransmission.
+ * When retransmission occurs as many as ref _RCR_+1 Timeout interrupt is issued (@ref Sn_IR_TIMEOUT = '1').
+ */
+// M20150401 : Rename SYMBOE ( Re-define error in a compile)
+// #define RCR                (_W5500_IO_BASE_ + (0x001B << 8) + (WIZCHIP_CREG_BLOCK << 3))
+#define _RCR_ (_W5500_IO_BASE_ + (0x001B << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief PPP LCP Request Timer register  in PPPoE mode(R/W)
+ * @details @ref PTIMER configures the time for sending LCP echo request. The unit of time is 25ms.
+ */
+#define PTIMER (_W5500_IO_BASE_ + (0x001C << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief PPP LCP Magic number register  in PPPoE mode(R/W)
+ * @details @ref PMAGIC configures the 4bytes magic number to be used in LCP negotiation.
+ */
+#define PMAGIC (_W5500_IO_BASE_ + (0x001D << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief PPP Destination MAC Register address(R/W)
+ * @details @ref PHAR configures the PPPoE server hardware address that is acquired during PPPoE connection process.
+ */
+#define PHAR (_W5500_IO_BASE_ + (0x001E << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief PPP Session Identification Register(R/W)
+ * @details @ref PSID configures the PPPoE sever session ID acquired during PPPoE connection process.
+ */
+#define PSID (_W5500_IO_BASE_ + (0x0024 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief PPP Maximum Segment Size(MSS) register(R/W)
+ * @details @ref PMRU configures the maximum receive unit of PPPoE.
+ */
+#define PMRU (_W5500_IO_BASE_ + (0x0026 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief Unreachable IP register address in UDP mode(R)
+ * @details W5500 receives an ICMP packet(Destination port unreachable) when data is sent to a port number
+ * which socket is not open and @ref IR_UNREACH bit of @ref IR becomes and @ref UIPR & @ref UPORTR indicates
+ * the destination IP address & port number respectively.
+ */
+#define UIPR (_W5500_IO_BASE_ + (0x0028 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief Unreachable Port register address in UDP mode(R)
+ * @details W5500 receives an ICMP packet(Destination port unreachable) when data is sent to a port number
+ * which socket is not open and @ref IR_UNREACH bit of @ref IR becomes and @ref UIPR & @ref UPORTR
+ * indicates the destination IP address & port number respectively.
+ */
+#define UPORTR (_W5500_IO_BASE_ + (0x002C << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief PHY Status Register(R/W)
+ * @details @ref PHYCFGR configures PHY operation mode and resets PHY. In addition, @ref PHYCFGR indicates the status of PHY such as duplex, Speed, Link.
+ */
+#define PHYCFGR (_W5500_IO_BASE_ + (0x002E << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+// Reserved			         (_W5500_IO_BASE_ + (0x002F << 8) + (WIZCHIP_CREG_BLOCK << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x0030 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x0031 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x0032 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x0033 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x0034 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x0035 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x0036 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x0037 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x0038 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+/**
+ * @ingroup Common_register_group
+ * @brief chip version register address(R)
+ * @details @ref VERSIONR always indicates the W5500 version as @b 0x04.
+ */
+#define VERSIONR (_W5500_IO_BASE_ + (0x0039 << 8) + (WIZCHIP_CREG_BLOCK << 3))
+
+//----------------------------- W5500 Socket Registers IOMAP -----------------------------
+/**
+ * @ingroup Socket_register_group
+ * @brief socket Mode register(R/W)
+ * @details @ref Sn_MR configures the option or protocol type of Socket n.\n\n
+ * Each bit of @ref Sn_MR defined as the following.
+ * <table>
+ * 		<tr>  <td>7</td> <td>6</td> <td>5</td> <td>4</td> <td>3</td> <td>2</td> <td>1</td> <td>0</td>   </tr>
+ * 		<tr>  <td>MULTI/MFEN</td> <td>BCASTB</td> <td>ND/MC/MMB</td> <td>UCASTB/MIP6B</td> <td>Protocol[3]</td> <td>Protocol[2]</td> <td>Protocol[1]</td> <td>Protocol[0]</td> </tr>
+ * </table>
+ * - @ref Sn_MR_MULTI	: Support UDP Multicasting
+ * - @ref Sn_MR_BCASTB	: Broadcast block <b>in UDP Multicasting</b>
+ * - @ref Sn_MR_ND		: No Delayed Ack(TCP) flag
+ * - @ref Sn_MR_MC   	: IGMP version used <b>in UDP mulitcasting</b>
+ * - @ref Sn_MR_MMB    	: Multicast Blocking <b>in @ref Sn_MR_MACRAW mode</b>
+ * - @ref Sn_MR_UCASTB	: Unicast Block <b>in UDP Multicating</b>
+ * - @ref Sn_MR_MIP6B   : IPv6 packet Blocking <b>in @ref Sn_MR_MACRAW mode</b>
+ * - <b>Protocol</b>
+ * <table>
+ * 		<tr>   <td><b>Protocol[3]</b></td> <td><b>Protocol[2]</b></td> <td><b>Protocol[1]</b></td> <td><b>Protocol[0]</b></td> <td>@b Meaning</td>   </tr>
+ * 		<tr>   <td>0</td> <td>0</td> <td>0</td> <td>0</td> <td>Closed</td>   </tr>
+ * 		<tr>   <td>0</td> <td>0</td> <td>0</td> <td>1</td> <td>TCP</td>   </tr>
+ * 		<tr>   <td>0</td> <td>0</td> <td>1</td> <td>0</td> <td>UDP</td>   </tr>
+ * 		<tr>   <td>0</td> <td>1</td> <td>0</td> <td>0</td> <td>MACRAW</td>   </tr>
+ * </table>
+ *	- @ref Sn_MR_MACRAW	: MAC LAYER RAW SOCK \n
+ *  - @ref Sn_MR_UDP		: UDP
+ *  - @ref Sn_MR_TCP		: TCP
+ *  - @ref Sn_MR_CLOSE	: Unused socket
+ *  @note MACRAW mode should be only used in Socket 0.
+ */
+#define Sn_MR(N) (_W5500_IO_BASE_ + (0x0000 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Socket command register(R/W)
+ * @details This is used to set the command for Socket n such as OPEN, CLOSE, CONNECT, LISTEN, SEND, and RECEIVE.\n
+ * After W5500 accepts the command, the @ref Sn_CR register is automatically cleared to 0x00.
+ * Even though @ref Sn_CR is cleared to 0x00, the command is still being processed.\n
+ * To check whether the command is completed or not, please check the @ref Sn_IR or @ref Sn_SR.
+ * - @ref Sn_CR_OPEN 		: Initialize or open socket.
+ * - @ref Sn_CR_LISTEN 		: Wait connection request in TCP mode(<b>Server mode</b>)
+ * - @ref Sn_CR_CONNECT 	: Send connection request in TCP mode(<b>Client mode</b>)
+ * - @ref Sn_CR_DISCON 		: Send closing request in TCP mode.
+ * - @ref Sn_CR_CLOSE   	: Close socket.
+ * - @ref Sn_CR_SEND    	: Update TX buffer pointer and send data.
+ * - @ref Sn_CR_SEND_MAC	: Send data with MAC address, so without ARP process.
+ * - @ref Sn_CR_SEND_KEEP 	: Send keep alive message.
+ * - @ref Sn_CR_RECV		: Update RX buffer pointer and receive data.
+ */
+#define Sn_CR(N) (_W5500_IO_BASE_ + (0x0001 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Socket interrupt register(R)
+ * @details @ref Sn_IR indicates the status of Socket Interrupt such as establishment, termination, receiving data, timeout).\n
+ * When an interrupt occurs and the corresponding bit of @ref Sn_IMR is  the corresponding bit of @ref Sn_IR becomes \n
+ * In order to clear the @ref Sn_IR bit, the host should write the bit to \n
+ * <table>
+ * 		<tr>  <td>7</td> <td>6</td> <td>5</td> <td>4</td> <td>3</td> <td>2</td> <td>1</td> <td>0</td>   </tr>
+ * 		<tr>  <td>Reserved</td> <td>Reserved</td> <td>Reserved</td> <td>SEND_OK</td> <td>TIMEOUT</td> <td>RECV</td> <td>DISCON</td> <td>CON</td> </tr>
+ * </table>
+ * - \ref Sn_IR_SENDOK : <b>SEND_OK Interrupt</b>
+ * - \ref Sn_IR_TIMEOUT : <b>TIMEOUT Interrupt</b>
+ * - \ref Sn_IR_RECV : <b>RECV Interrupt</b>
+ * - \ref Sn_IR_DISCON : <b>DISCON Interrupt</b>
+ * - \ref Sn_IR_CON : <b>CON Interrupt</b>
+ */
+#define Sn_IR(N) (_W5500_IO_BASE_ + (0x0002 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Socket status register(R)
+ * @details @ref Sn_SR indicates the status of Socket n.\n
+ * The status of Socket n is changed by @ref Sn_CR or some special control packet as SYN, FIN packet in TCP.
+ * @par Normal status
+ * - @ref SOCK_CLOSED 		: Closed
+ * - @ref SOCK_INIT   		: Initiate state
+ * - @ref SOCK_LISTEN    	: Listen state
+ * - @ref SOCK_ESTABLISHED 	: Success to connect
+ * - @ref SOCK_CLOSE_WAIT   : Closing state
+ * - @ref SOCK_UDP   		: UDP socket
+ * - @ref SOCK_MACRAW  		: MAC raw mode socket
+ *@par Temporary status during changing the status of Socket n.
+ * - @ref SOCK_SYNSENT   	: This indicates Socket n sent the connect-request packet (SYN packet) to a peer.
+ * - @ref SOCK_SYNRECV    	: It indicates Socket n successfully received the connect-request packet (SYN packet) from a peer.
+ * - @ref SOCK_FIN_WAIT		: Connection state
+ * - @ref SOCK_CLOSING		: Closing state
+ * - @ref SOCK_TIME_WAIT	: Closing state
+ * - @ref SOCK_LAST_ACK 	: Closing state
+ */
+#define Sn_SR(N) (_W5500_IO_BASE_ + (0x0003 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief source port register(R/W)
+ * @details @ref Sn_PORT configures the source port number of Socket n.
+ * It is valid when Socket n is used in TCP/UDP mode. It should be set before OPEN command is ordered.
+ */
+#define Sn_PORT(N) (_W5500_IO_BASE_ + (0x0004 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Peer MAC register address(R/W)
+ * @details @ref Sn_DHAR configures the destination hardware address of Socket n when using SEND_MAC command in UDP mode or
+ * it indicates that it is acquired in ARP-process by CONNECT/SEND command.
+ */
+#define Sn_DHAR(N) (_W5500_IO_BASE_ + (0x0006 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Peer IP register address(R/W)
+ * @details @ref Sn_DIPR configures or indicates the destination IP address of Socket n. It is valid when Socket n is used in TCP/UDP mode.
+ * In TCP client mode, it configures an IP address of TCP serverbefore CONNECT command.
+ * In TCP server mode, it indicates an IP address of TCP clientafter successfully establishing connection.
+ * In UDP mode, it configures an IP address of peer to be received the UDP packet by SEND or SEND_MAC command.
+ */
+#define Sn_DIPR(N) (_W5500_IO_BASE_ + (0x000C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Peer port register address(R/W)
+ * @details @ref Sn_DPORT configures or indicates the destination port number of Socket n. It is valid when Socket n is used in TCP/UDP mode.
+ * In TCP clientmode, it configures the listen port number of TCP serverbefore CONNECT command.
+ * In TCP Servermode, it indicates the port number of TCP client after successfully establishing connection.
+ * In UDP mode, it configures the port number of peer to be transmitted the UDP packet by SEND/SEND_MAC command.
+ */
+#define Sn_DPORT(N) (_W5500_IO_BASE_ + (0x0010 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Maximum Segment Size(Sn_MSSR0) register address(R/W)
+ * @details @ref Sn_MSSR configures or indicates the MTU(Maximum Transfer Unit) of Socket n.
+ */
+#define Sn_MSSR(N) (_W5500_IO_BASE_ + (0x0012 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+// Reserved			         (_W5500_IO_BASE_ + (0x0014 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief IP Type of Service(TOS) Register(R/W)
+ * @details @ref Sn_TOS configures the TOS(Type Of Service field in IP Header) of Socket n.
+ * It is set before OPEN command.
+ */
+#define Sn_TOS(N) (_W5500_IO_BASE_ + (0x0015 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+/**
+ * @ingroup Socket_register_group
+ * @brief IP Time to live(TTL) Register(R/W)
+ * @details @ref Sn_TTL configures the TTL(Time To Live field in IP header) of Socket n.
+ * It is set before OPEN command.
+ */
+#define Sn_TTL(N) (_W5500_IO_BASE_ + (0x0016 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x0017 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x0018 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x0019 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x001A << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x001B << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x001C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+// Reserved			         (_W5500_IO_BASE_ + (0x001D << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Receive memory size register(R/W)
+ * @details @ref Sn_RXBUF_SIZE configures the RX buffer block size of Socket n.
+ * Socket n RX Buffer Block size can be configured with 1,2,4,8, and 16 Kbytes.
+ * If a different size is configured, the data cannot be normally received from a peer.
+ * Although Socket n RX Buffer Block size is initially configured to 2Kbytes,
+ * user can re-configure its size using @ref Sn_RXBUF_SIZE. The total sum of @ref Sn_RXBUF_SIZE can not be exceed 16Kbytes.
+ * When exceeded, the data reception error is occurred.
+ */
+#define Sn_RXBUF_SIZE(N) (_W5500_IO_BASE_ + (0x001E << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Transmit memory size register(R/W)
+ * @details @ref Sn_TXBUF_SIZE configures the TX buffer block size of Socket n. Socket n TX Buffer Block size can be configured with 1,2,4,8, and 16 Kbytes.
+ * If a different size is configured, the data can�t be normally transmitted to a peer.
+ * Although Socket n TX Buffer Block size is initially configured to 2Kbytes,
+ * user can be re-configure its size using @ref Sn_TXBUF_SIZE. The total sum of @ref Sn_TXBUF_SIZE can not be exceed 16Kbytes.
+ * When exceeded, the data transmission error is occurred.
+ */
+#define Sn_TXBUF_SIZE(N) (_W5500_IO_BASE_ + (0x001F << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Transmit free memory size register(R)
+ * @details @ref Sn_TX_FSR indicates the free size of Socket n TX Buffer Block. It is initialized to the configured size by @ref Sn_TXBUF_SIZE.
+ * Data bigger than @ref Sn_TX_FSR should not be saved in the Socket n TX Buffer because the bigger data overwrites the previous saved data not yet sent.
+ * Therefore, check before saving the data to the Socket n TX Buffer, and if data is equal or smaller than its checked size,
+ * transmit the data with SEND/SEND_MAC command after saving the data in Socket n TX buffer. But, if data is bigger than its checked size,
+ * transmit the data after dividing into the checked size and saving in the Socket n TX buffer.
+ */
+#define Sn_TX_FSR(N) (_W5500_IO_BASE_ + (0x0020 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Transmit memory read pointer register address(R)
+ * @details @ref Sn_TX_RD is initialized by OPEN command. However, if Sn_MR(P[3:0]) is TCP mode(001, it is re-initialized while connecting with TCP.
+ * After its initialization, it is auto-increased by SEND command.
+ * SEND command transmits the saved data from the current @ref Sn_TX_RD to the @ref Sn_TX_WR in the Socket n TX Buffer.
+ * After transmitting the saved data, the SEND command increases the @ref Sn_TX_RD as same as the @ref Sn_TX_WR.
+ * If its increment value exceeds the maximum value 0xFFFF, (greater than 0x10000 and the carry bit occurs),
+ * then the carry bit is ignored and will automatically update with the lower 16bits value.
+ */
+#define Sn_TX_RD(N) (_W5500_IO_BASE_ + (0x0022 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Transmit memory write pointer register address(R/W)
+ * @details @ref Sn_TX_WR is initialized by OPEN command. However, if Sn_MR(P[3:0]) is TCP mode(001, it is re-initialized while connecting with TCP.\n
+ * It should be read or be updated like as follows.\n
+ * 1. Read the starting address for saving the transmitting data.\n
+ * 2. Save the transmitting data from the starting address of Socket n TX buffer.\n
+ * 3. After saving the transmitting data, update @ref Sn_TX_WR to the increased value as many as transmitting data size.
+ * If the increment value exceeds the maximum value 0xFFFF(greater than 0x10000 and the carry bit occurs),
+ * then the carry bit is ignored and will automatically update with the lower 16bits value.\n
+ * 4. Transmit the saved data in Socket n TX Buffer by using SEND/SEND command
+ */
+#define Sn_TX_WR(N) (_W5500_IO_BASE_ + (0x0024 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Received data size register(R)
+ * @details @ref Sn_RX_RSR indicates the data size received and saved in Socket n RX Buffer.
+ * @ref Sn_RX_RSR does not exceed the @ref Sn_RXBUF_SIZE and is calculated as the difference between
+ * �Socket n RX Write Pointer (@ref Sn_RX_WR)and �Socket n RX Read Pointer (@ref Sn_RX_RD)
+ */
+#define Sn_RX_RSR(N) (_W5500_IO_BASE_ + (0x0026 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Read point of Receive memory(R/W)
+ * @details @ref Sn_RX_RD is initialized by OPEN command. Make sure to be read or updated as follows.\n
+ * 1. Read the starting save address of the received data.\n
+ * 2. Read data from the starting address of Socket n RX Buffer.\n
+ * 3. After reading the received data, Update @ref Sn_RX_RD to the increased value as many as the reading size.
+ * If the increment value exceeds the maximum value 0xFFFF, that is, is greater than 0x10000 and the carry bit occurs,
+ * update with the lower 16bits value ignored the carry bit.\n
+ * 4. Order RECV command is for notifying the updated @ref Sn_RX_RD to W5500.
+ */
+#define Sn_RX_RD(N) (_W5500_IO_BASE_ + (0x0028 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Write point of Receive memory(R)
+ * @details @ref Sn_RX_WR is initialized by OPEN command and it is auto-increased by the data reception.
+ * If the increased value exceeds the maximum value 0xFFFF, (greater than 0x10000 and the carry bit occurs),
+ * then the carry bit is ignored and will automatically update with the lower 16bits value.
+ */
+#define Sn_RX_WR(N) (_W5500_IO_BASE_ + (0x002A << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief socket interrupt mask register(R)
+ * @details @ref Sn_IMR masks the interrupt of Socket n.
+ * Each bit corresponds to each bit of @ref Sn_IR. When a Socket n Interrupt is occurred and the corresponding bit of @ref Sn_IMR is
+ * the corresponding bit of @ref Sn_IR becomes  When both the corresponding bit of @ref Sn_IMR and @ref Sn_IR are and the n-th bit of @ref IR is
+ * Host is interrupted by asserted INTn PIN to low.
+ */
+#define Sn_IMR(N) (_W5500_IO_BASE_ + (0x002C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Fragment field value in IP header register(R/W)
+ * @details @ref Sn_FRAG configures the FRAG(Fragment field in IP header).
+ */
+#define Sn_FRAG(N) (_W5500_IO_BASE_ + (0x002D << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+/**
+ * @ingroup Socket_register_group
+ * @brief Keep Alive Timer register(R/W)
+ * @details @ref Sn_KPALVTR configures the transmitting timer of �KEEP ALIVE(KA)packet of SOCKETn. It is valid only in TCP mode,
+ * and ignored in other modes. The time unit is 5s.
+ * KA packet is transmittable after @ref Sn_SR is changed to SOCK_ESTABLISHED and after the data is transmitted or received to/from a peer at least once.
+ * In case of '@ref Sn_KPALVTR > 0', W5500 automatically transmits KA packet after time-period for checking the TCP connection (Auto-keepalive-process).
+ * In case of '@ref Sn_KPALVTR = 0', Auto-keep-alive-process will not operate,
+ * and KA packet can be transmitted by SEND_KEEP command by the host (Manual-keep-alive-process).
+ * Manual-keep-alive-process is ignored in case of '@ref Sn_KPALVTR > 0'.
+ */
+#define Sn_KPALVTR(N) (_W5500_IO_BASE_ + (0x002F << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+// #define Sn_TSR(N)          (_W5500_IO_BASE_ + (0x0030 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3))
+
+//----------------------------- W5500 Register values  -----------------------------
+
+/* MODE register values */
+/**
+ * @brief Reset
+ * @details If this bit is  All internal registers will be initialized. It will be automatically cleared as after S/W reset.
+ */
+#define MR_RST 0x80
+
+/**
+ * @brief Wake on LAN
+ * @details 0 : Disable WOL mode\n
+ * 1 : Enable WOL mode\n
+ * If WOL mode is enabled and the received magic packet over UDP has been normally processed, the Interrupt PIN (INTn) asserts to low.
+ * When using WOL mode, the UDP Socket should be opened with any source port number. (Refer to Socket n Mode Register (@ref Sn_MR) for opening Socket.)
+ * @note The magic packet over UDP supported by W5500 consists of 6 bytes synchronization stream (xFFFFFFFFFFFF and
+ * 16 times Target MAC address stream in UDP payload. The options such like password are ignored. You can use any UDP source port number for WOL mode.
+ */
+#define MR_WOL 0x20
+
+/**
+ * @brief Ping block
+ * @details 0 : Disable Ping block\n
+ * 1 : Enable Ping block\n
+ * If the bit is  it blocks the response to a ping request.
+ */
+#define MR_PB 0x10
+
+/**
+ * @brief Enable PPPoE
+ * @details 0 : DisablePPPoE mode\n
+ * 1 : EnablePPPoE mode\n
+ * If you use ADSL, this bit should be
+ */
+#define MR_PPPOE 0x08
+
+/**
+ * @brief Enable UDP_FORCE_ARP CHECHK
+ * @details 0 : Disable Force ARP mode\n
+ * 1 : Enable Force ARP mode\n
+ * In Force ARP mode, It forces on sending ARP Request whenever data is sent.
+ */
+#define MR_FARP 0x02
+
+/* IR register values */
+/**
+ * @brief Check IP conflict.
+ * @details Bit is set as when own source IP address is same with the sender IP address in the received ARP request.
+ */
+#define IR_CONFLICT 0x80
+
+/**
+ * @brief Get the destination unreachable message in UDP sending.
+ * @details When receiving the ICMP (Destination port unreachable) packet, this bit is set as
+ * When this bit is  Destination Information such as IP address and Port number may be checked with the corresponding @ref UIPR & @ref UPORTR.
+ */
+#define IR_UNREACH 0x40
+
+/**
+ * @brief Get the PPPoE close message.
+ * @details When PPPoE is disconnected during PPPoE mode, this bit is set.
+ */
+#define IR_PPPoE 0x20
+
+/**
+ * @brief Get the magic packet interrupt.
+ * @details When WOL mode is enabled and receives the magic packet over UDP, this bit is set.
+ */
+#define IR_MP 0x10
+
+/* PHYCFGR register value */
+#define PHYCFGR_RST ~(1 << 7) //< For PHY reset, must operate AND mask.
+#define PHYCFGR_OPMD (1 << 6) // Configre PHY with OPMDC value
+#define PHYCFGR_OPMDC_ALLA (7 << 3)
+#define PHYCFGR_OPMDC_PDOWN (6 << 3)
+#define PHYCFGR_OPMDC_NA (5 << 3)
+#define PHYCFGR_OPMDC_100FA (4 << 3)
+#define PHYCFGR_OPMDC_100F (3 << 3)
+#define PHYCFGR_OPMDC_100H (2 << 3)
+#define PHYCFGR_OPMDC_10F (1 << 3)
+#define PHYCFGR_OPMDC_10H (0 << 3)
+#define PHYCFGR_DPX_FULL (1 << 2)
+#define PHYCFGR_DPX_HALF (0 << 2)
+#define PHYCFGR_SPD_100 (1 << 1)
+#define PHYCFGR_SPD_10 (0 << 1)
+#define PHYCFGR_LNK_ON (1 << 0)
+#define PHYCFGR_LNK_OFF (0 << 0)
+
+/* IMR register values */
+/**
+ * @brief IP Conflict Interrupt Mask.
+ * @details 0: Disable IP Conflict Interrupt\n
+ * 1: Enable IP Conflict Interrupt
+ */
+#define IM_IR7 0x80
+
+/**
+ * @brief Destination unreachable Interrupt Mask.
+ * @details 0: Disable Destination unreachable Interrupt\n
+ * 1: Enable Destination unreachable Interrupt
+ */
+#define IM_IR6 0x40
+
+/**
+ * @brief PPPoE Close Interrupt Mask.
+ * @details 0: Disable PPPoE Close Interrupt\n
+ * 1: Enable PPPoE Close Interrupt
+ */
+#define IM_IR5 0x20
+
+/**
+ * @brief Magic Packet Interrupt Mask.
+ * @details 0: Disable Magic Packet Interrupt\n
+ * 1: Enable Magic Packet Interrupt
+ */
+#define IM_IR4 0x10
+
+/* Sn_MR Default values */
+/**
+ * @brief Support UDP Multicasting
+ * @details 0 : disable Multicasting\n
+ * 1 : enable Multicasting\n
+ * This bit is applied only during UDP mode(P[3:0] = 010.\n
+ * To use multicasting, @ref Sn_DIPR & @ref Sn_DPORT should be respectively configured with the multicast group IP address & port number
+ * before Socket n is opened by OPEN command of @ref Sn_CR.
+ */
+#define Sn_MR_MULTI 0x80
+
+/**
+ * @brief Broadcast block in UDP Multicasting.
+ * @details 0 : disable Broadcast Blocking\n
+ * 1 : enable Broadcast Blocking\n
+ * This bit blocks to receive broadcasting packet during UDP mode(P[3:0] = 010.\m
+ * In addition, This bit does when MACRAW mode(P[3:0] = 100
+ */
+#define Sn_MR_BCASTB 0x40
+
+/**
+ * @brief No Delayed Ack(TCP), Multicast flag
+ * @details 0 : Disable No Delayed ACK option\n
+ * 1 : Enable No Delayed ACK option\n
+ * This bit is applied only during TCP mode (P[3:0] = 001.\n
+ * When this bit is  It sends the ACK packet without delay as soon as a Data packet is received from a peer.\n
+ * When this bit is  It sends the ACK packet after waiting for the timeout time configured by @ref _RTR_.
+ */
+#define Sn_MR_ND 0x20
+
+/**
+ * @brief Unicast Block in UDP Multicasting
+ * @details 0 : disable Unicast Blocking\n
+ * 1 : enable Unicast Blocking\n
+ * This bit blocks receiving the unicast packet during UDP mode(P[3:0] = 010 and MULTI =
+ */
+#define Sn_MR_UCASTB 0x10
+
+/**
+ * @brief MAC LAYER RAW SOCK
+ * @details This configures the protocol mode of Socket n.
+ * @note MACRAW mode should be only used in Socket 0.
+ */
+#define Sn_MR_MACRAW 0x04
+
+#define Sn_MR_IPRAW 0x03 /**< IP LAYER RAW SOCK */
+
+/**
+ * @brief UDP
+ * @details This configures the protocol mode of Socket n.
+ */
+#define Sn_MR_UDP 0x02
+
+/**
+ * @brief TCP
+ * @details This configures the protocol mode of Socket n.
+ */
+#define Sn_MR_TCP 0x01
+
+/**
+ * @brief Unused socket
+ * @details This configures the protocol mode of Socket n.
+ */
+#define Sn_MR_CLOSE 0x00
+
+/* Sn_MR values used with Sn_MR_MACRAW */
+/**
+ * @brief MAC filter enable in @ref Sn_MR_MACRAW mode
+ * @details 0 : disable MAC Filtering\n
+ * 1 : enable MAC Filtering\n
+ * This bit is applied only during MACRAW mode(P[3:0] = 100.\n
+ * When set as  W5500 can only receive broadcasting packet or packet sent to itself.
+ * When this bit is  W5500 can receive all packets on Ethernet.
+ * If user wants to implement Hybrid TCP/IP stack,
+ * it is recommended that this bit is set as for reducing host overhead to process the all received packets.
+ */
+#define Sn_MR_MFEN Sn_MR_MULTI
+
+/**
+ * @brief Multicast Blocking in @ref Sn_MR_MACRAW mode
+ * @details 0 : using IGMP version 2\n
+ * 1 : using IGMP version 1\n
+ * This bit is applied only during UDP mode(P[3:0] = 010 and MULTI =
+ * It configures the version for IGMP messages (Join/Leave/Report).
+ */
+#define Sn_MR_MMB Sn_MR_ND
+
+/**
+ * @brief IPv6 packet Blocking in @ref Sn_MR_MACRAW mode
+ * @details 0 : disable IPv6 Blocking\n
+ * 1 : enable IPv6 Blocking\n
+ * This bit is applied only during MACRAW mode (P[3:0] = 100. It blocks to receiving the IPv6 packet.
+ */
+#define Sn_MR_MIP6B Sn_MR_UCASTB
+
+/* Sn_MR value used with Sn_MR_UDP & Sn_MR_MULTI */
+/**
+ * @brief IGMP version used in UDP mulitcasting
+ * @details 0 : disable Multicast Blocking\n
+ * 1 : enable Multicast Blocking\n
+ * This bit is applied only when MACRAW mode(P[3:0] = 100. It blocks to receive the packet with multicast MAC address.
+ */
+#define Sn_MR_MC Sn_MR_ND
+
+/* Sn_MR alternate values */
+/**
+ * @brief For Berkeley Socket API
+ */
+#define SOCK_STREAM Sn_MR_TCP
+
+/**
+ * @brief For Berkeley Socket API
+ */
+#define SOCK_DGRAM Sn_MR_UDP
+
+/* Sn_CR values */
+/**
+ * @brief Initialize or open socket
+ * @details Socket n is initialized and opened according to the protocol selected in Sn_MR(P3:P0).
+ * The table below shows the value of @ref Sn_SR corresponding to @ref Sn_MR.\n
+ * <table>
+ *   <tr>  <td>\b Sn_MR (P[3:0])</td> <td>\b Sn_SR</td>            		 </tr>
+ *   <tr>  <td>Sn_MR_CLOSE  (000)</td> <td></td>         	   		 </tr>
+ *   <tr>  <td>Sn_MR_TCP  (001)</td> <td>SOCK_INIT (0x13)</td>  		 </tr>
+ *   <tr>  <td>Sn_MR_UDP  (010)</td>  <td>SOCK_UDP (0x22)</td>  		 </tr>
+ *   <tr>  <td>S0_MR_MACRAW  (100)</td>  <td>SOCK_MACRAW (0x02)</td>  </tr>
+ * </table>
+ */
+#define Sn_CR_OPEN 0x01
+
+/**
+ * @brief Wait connection request in TCP mode(Server mode)
+ * @details This is valid only in TCP mode (\ref Sn_MR(P3:P0) = \ref Sn_MR_TCP).
+ * In this mode, Socket n operates as a TCP serverand waits for  connection-request (SYN packet) from any TCP client
+ * The @ref Sn_SR changes the state from \ref SOCK_INIT to \ref SOCKET_LISTEN.
+ * When a TCP clientconnection request is successfully established,
+ * the @ref Sn_SR changes from SOCK_LISTEN to SOCK_ESTABLISHED and the @ref Sn_IR(0) becomes
+ * But when a TCP clientconnection request is failed, @ref Sn_IR(3) becomes and the status of @ref Sn_SR changes to SOCK_CLOSED.
+ */
+#define Sn_CR_LISTEN 0x02
+
+/**
+ * @brief Send connection request in TCP mode(Client mode)
+ * @details  To connect, a connect-request (SYN packet) is sent to <b>TCP server</b>configured by @ref Sn_DIPR & Sn_DPORT(destination address & port).
+ * If the connect-request is successful, the @ref Sn_SR is changed to @ref SOCK_ESTABLISHED and the Sn_IR(0) becomes \n\n
+ * The connect-request fails in the following three cases.\n
+ * 1. When a @b ARPTO occurs (@ref Sn_IR[3] =  ) because destination hardware address is not acquired through the ARP-process.\n
+ * 2. When a @b SYN/ACK packet is not received and @b TCPTO (Sn_IR(3) =  )\n
+ * 3. When a @b RST packet is received instead of a @b SYN/ACK packet. In these cases, @ref Sn_SR is changed to @ref SOCK_CLOSED.
+ * @note This is valid only in TCP mode and operates when Socket n acts as <b>TCP client</b>
+ */
+#define Sn_CR_CONNECT 0x04
+
+/**
+ * @brief Send closing request in TCP mode
+ * @details Regardless of <b>TCP server</b>or <b>TCP client</b> the DISCON command processes the disconnect-process (b>Active close</b>or <b>Passive close</b>.\n
+ * @par Active close
+ * it transmits disconnect-request(FIN packet) to the connected peer\n
+ * @par Passive close
+ * When FIN packet is received from peer, a FIN packet is replied back to the peer.\n
+ * @details When the disconnect-process is successful (that is, FIN/ACK packet is received successfully), @ref Sn_SR is changed to @ref SOCK_CLOSED.\n
+ * Otherwise, TCPTO occurs (\ref Sn_IR(3)='1') and then @ref Sn_SR is changed to @ref SOCK_CLOSED.
+ * @note Valid only in TCP mode.
+ */
+#define Sn_CR_DISCON 0x08
+
+/**
+ * @brief Close socket
+ * @details Sn_SR is changed to @ref SOCK_CLOSED.
+ */
+#define Sn_CR_CLOSE 0x10
+
+/**
+ * @brief Update TX buffer pointer and send data
+ * @details SEND transmits all the data in the Socket n TX buffer.\n
+ * For more details, please refer to Socket n TX Free Size Register (@ref Sn_TX_FSR), Socket n,
+ * TX Write Pointer Register(@ref Sn_TX_WR), and Socket n TX Read Pointer Register(@ref Sn_TX_RD).
+ */
+#define Sn_CR_SEND 0x20
+
+/**
+ * @brief Send data with MAC address, so without ARP process
+ * @details The basic operation is same as SEND.\n
+ * Normally SEND transmits data after destination hardware address is acquired by the automatic ARP-process(Address Resolution Protocol).\n
+ * But SEND_MAC transmits data without the automatic ARP-process.\n
+ * In this case, the destination hardware address is acquired from @ref Sn_DHAR configured by host, instead of APR-process.
+ * @note Valid only in UDP mode.
+ */
+#define Sn_CR_SEND_MAC 0x21
+
+/**
+ * @brief Send keep alive message
+ * @details It checks the connection status by sending 1byte keep-alive packet.\n
+ * If the peer can not respond to the keep-alive packet during timeout time, the connection is terminated and the timeout interrupt will occur.
+ * @note Valid only in TCP mode.
+ */
+#define Sn_CR_SEND_KEEP 0x22
+
+/**
+ * @brief Update RX buffer pointer and receive data
+ * @details RECV completes the processing of the received data in Socket n RX Buffer by using a RX read pointer register (@ref Sn_RX_RD).\n
+ * For more details, refer to Socket n RX Received Size Register (@ref Sn_RX_RSR), Socket n RX Write Pointer Register (@ref Sn_RX_WR),
+ * and Socket n RX Read Pointer Register (@ref Sn_RX_RD).
+ */
+#define Sn_CR_RECV 0x40
+
+/* Sn_IR values */
+/**
+ * @brief SEND_OK Interrupt
+ * @details This is issued when SEND command is completed.
+ */
+#define Sn_IR_SENDOK 0x10
+
+/**
+ * @brief TIMEOUT Interrupt
+ * @details This is issued when ARPTO or TCPTO occurs.
+ */
+#define Sn_IR_TIMEOUT 0x08
+
+/**
+ * @brief RECV Interrupt
+ * @details This is issued whenever data is received from a peer.
+ */
+#define Sn_IR_RECV 0x04
+
+/**
+ * @brief DISCON Interrupt
+ * @details This is issued when FIN or FIN/ACK packet is received from a peer.
+ */
+#define Sn_IR_DISCON 0x02
+
+/**
+ * @brief CON Interrupt
+ * @details This is issued one time when the connection with peer is successful and then @ref Sn_SR is changed to @ref SOCK_ESTABLISHED.
+ */
+#define Sn_IR_CON 0x01
+
+/* Sn_SR values */
+/**
+ * @brief Closed
+ * @details This indicates that Socket n is released.\n
+ * When DICON, CLOSE command is ordered, or when a timeout occurs, it is changed to @ref SOCK_CLOSED regardless of previous status.
+ */
+#define SOCK_CLOSED 0x00
+
+/**
+ * @brief Initiate state
+ * @details This indicates Socket n is opened with TCP mode.\n
+ * It is changed to @ref SOCK_INIT when @ref Sn_MR(P[3:0]) = 001 and OPEN command is ordered.\n
+ * After @ref SOCK_INIT, user can use LISTEN /CONNECT command.
+ */
+#define SOCK_INIT 0x13
+
+/**
+ * @brief Listen state
+ * @details This indicates Socket n is operating as <b>TCP server</b>mode and waiting for connection-request (SYN packet) from a peer <b>TCP client</b>.\n
+ * It will change to @ref SOCK_ESTALBLISHED when the connection-request is successfully accepted.\n
+ * Otherwise it will change to @ref SOCK_CLOSED after TCPTO @ref Sn_IR(TIMEOUT) = '1') is occurred.
+ */
+#define SOCK_LISTEN 0x14
+
+/**
+ * @brief Connection state
+ * @details This indicates Socket n sent the connect-request packet (SYN packet) to a peer.\n
+ * It is temporarily shown when @ref Sn_SR is changed from @ref SOCK_INIT to @ref SOCK_ESTABLISHED by CONNECT command.\n
+ * If connect-accept(SYN/ACK packet) is received from the peer at SOCK_SYNSENT, it changes to @ref SOCK_ESTABLISHED.\n
+ * Otherwise, it changes to @ref SOCK_CLOSED after TCPTO (@ref Sn_IR[TIMEOUT] = '1') is occurred.
+ */
+#define SOCK_SYNSENT 0x15
+
+/**
+ * @brief Connection state
+ * @details It indicates Socket n successfully received the connect-request packet (SYN packet) from a peer.\n
+ * If socket n sends the response (SYN/ACK  packet) to the peer successfully,  it changes to @ref SOCK_ESTABLISHED. \n
+ * If not, it changes to @ref SOCK_CLOSED after timeout (@ref Sn_IR[TIMEOUT] = '1') is occurred.
+ */
+#define SOCK_SYNRECV 0x16
+
+/**
+ * @brief Success to connect
+ * @details This indicates the status of the connection of Socket n.\n
+ * It changes to @ref SOCK_ESTABLISHED when the <b>TCP SERVER</b>processed the SYN packet from the <b>TCP CLIENT</b>during @ref SOCK_LISTEN, or
+ * when the CONNECT command is successful.\n
+ * During @ref SOCK_ESTABLISHED, DATA packet can be transferred using SEND or RECV command.
+ */
+#define SOCK_ESTABLISHED 0x17
+
+/**
+ * @brief Closing state
+ * @details These indicate Socket n is closing.\n
+ * These are shown in disconnect-process such as active-close and passive-close.\n
+ * When Disconnect-process is successfully completed, or when timeout occurs, these change to @ref SOCK_CLOSED.
+ */
+#define SOCK_FIN_WAIT 0x18
+
+/**
+ * @brief Closing state
+ * @details These indicate Socket n is closing.\n
+ * These are shown in disconnect-process such as active-close and passive-close.\n
+ * When Disconnect-process is successfully completed, or when timeout occurs, these change to @ref SOCK_CLOSED.
+ */
+#define SOCK_CLOSING 0x1A
+
+/**
+ * @brief Closing state
+ * @details These indicate Socket n is closing.\n
+ * These are shown in disconnect-process such as active-close and passive-close.\n
+ * When Disconnect-process is successfully completed, or when timeout occurs, these change to @ref SOCK_CLOSED.
+ */
+#define SOCK_TIME_WAIT 0x1B
+
+/**
+ * @brief Closing state
+ * @details This indicates Socket n received the disconnect-request (FIN packet) from the connected peer.\n
+ * This is half-closing status, and data can be transferred.\n
+ * For full-closing, DISCON command is used. But For just-closing, CLOSE command is used.
+ */
+#define SOCK_CLOSE_WAIT 0x1C
+
+/**
+ * @brief Closing state
+ * @details This indicates Socket n is waiting for the response (FIN/ACK packet) to the disconnect-request (FIN packet) by passive-close.\n
+ * It changes to @ref SOCK_CLOSED when Socket n received the response successfully, or when timeout(@ref Sn_IR[TIMEOUT] = '1') is occurred.
+ */
+#define SOCK_LAST_ACK 0x1D
+
+/**
+ * @brief UDP socket
+ * @details This indicates Socket n is opened in UDP mode(@ref Sn_MR(P[3:0]) = '010').\n
+ * It changes to SOCK_UDP when @ref Sn_MR(P[3:0]) = '010' and @ref Sn_CR_OPEN command is ordered.\n
+ * Unlike TCP mode, data can be transfered without the connection-process.
+ */
+#define SOCK_UDP 0x22
+
+#define SOCK_IPRAW 0x32 /**< IP raw mode socket */
+
+/**
+ * @brief MAC raw mode socket
+ * @details This indicates Socket 0 is opened in MACRAW mode (S0_MR(P[3:0]) = 100and is valid only in Socket 0.\n
+ * It changes to SOCK_MACRAW when S0_MR(P[3:0] = 100and OPEN command is ordered.\n
+ * Like UDP mode socket, MACRAW mode Socket 0 can transfer a MAC packet (Ethernet frame) without the connection-process.
+ */
+#define SOCK_MACRAW 0x42
+
+// #define SOCK_PPPOE                   0x5F
+
+/* IP PROTOCOL */
+#define IPPROTO_IP 0    //< Dummy for IP
+#define IPPROTO_ICMP 1  //< Control message protocol
+#define IPPROTO_IGMP 2  //< Internet group management protocol
+#define IPPROTO_GGP 3   //< Gateway^2 (deprecated)
+#define IPPROTO_TCP 6   //< TCP
+#define IPPROTO_PUP 12  //< PUP
+#define IPPROTO_UDP 17  //< UDP
+#define IPPROTO_IDP 22  //< XNS idp
+#define IPPROTO_ND 77   //< UNOFFICIAL net disk protocol
+#define IPPROTO_RAW 255 //< Raw IP packet
+
+/**
+ * @brief Enter a critical section
+ *
+ * @details It is provided to protect your shared code which are executed without distribution. \n \n
+ *
+ * In non-OS environment, It can be just implemented by disabling whole interrupt.\n
+ * In OS environment, You can replace it to critical section api supported by OS.
+ *
+ * \sa WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF()
+ * \sa WIZCHIP_CRITICAL_EXIT()
+ */
+#define WIZCHIP_CRITICAL_ENTER() WIZCHIP.CRIS._enter()
+
+#ifdef _exit
+#undef _exit
+#endif
+
+/**
+ * @brief Exit a critical section
+ *
+ * @details It is provided to protect your shared code which are executed without distribution. \n\n
+ *
+ * In non-OS environment, It can be just implemented by disabling whole interrupt. \n
+ * In OS environment, You can replace it to critical section api supported by OS.
+ *
+ * @sa WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF()
+ * @sa WIZCHIP_CRITICAL_ENTER()
+ */
+#define WIZCHIP_CRITICAL_EXIT() WIZCHIP.CRIS._exit()
+
+    ////////////////////////
+    // Basic I/O Function //
+    ////////////////////////
+
+    /**
+     * @ingroup Basic_IO_function
+     * @brief It reads 1 byte value from a register.
+     * @param AddrSel Register address
+     * @return The value of register
+     */
+    uint8_t WIZCHIP_READ(uint32_t AddrSel);
+
+    /**
+     * @ingroup Basic_IO_function
+     * @brief It writes 1 byte value to a register.
+     * @param AddrSel Register address
+     * @param wb Write data
+     * @return void
+     */
+    void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb);
+
+    /**
+     * @ingroup Basic_IO_function
+     * @brief It reads sequence data from registers.
+     * @param AddrSel Register address
+     * @param pBuf Pointer buffer to read data
+     * @param len Data length
+     */
+    void WIZCHIP_READ_BUF(uint32_t AddrSel, uint8_t *pBuf, uint16_t len);
+
+    /**
+     * @ingroup Basic_IO_function
+     * @brief It writes sequence data to registers.
+     * @param AddrSel Register address
+     * @param pBuf Pointer buffer to write data
+     * @param len Data length
+     */
+    void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t *pBuf, uint16_t len);
+
+/////////////////////////////////
+// Common Register I/O function //
+/////////////////////////////////
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set Mode Register
+ * @param (uint8_t)mr The value to be set.
+ * @sa getMR()
+ */
+#define setMR(mr) \
+    WIZCHIP_WRITE(MR, mr)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get Mode Register
+ * @return uint8_t. The value of Mode register.
+ * @sa setMR()
+ */
+#define getMR() \
+    WIZCHIP_READ(MR)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set gateway IP address
+ * @param (uint8_t*)gar Pointer variable to set gateway IP address. It should be allocated 4 bytes.
+ * @sa getGAR()
+ */
+#define setGAR(gar) \
+    WIZCHIP_WRITE_BUF(GAR, gar, 4)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get gateway IP address
+ * @param (uint8_t*)gar Pointer variable to get gateway IP address. It should be allocated 4 bytes.
+ * @sa setGAR()
+ */
+#define getGAR(gar) \
+    WIZCHIP_READ_BUF(GAR, gar, 4)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set subnet mask address
+ * @param (uint8_t*)subr Pointer variable to set subnet mask address. It should be allocated 4 bytes.
+ * @sa getSUBR()
+ */
+#define setSUBR(subr) \
+    WIZCHIP_WRITE_BUF(SUBR, subr, 4)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get subnet mask address
+ * @param (uint8_t*)subr Pointer variable to get subnet mask address. It should be allocated 4 bytes.
+ * @sa setSUBR()
+ */
+#define getSUBR(subr) \
+    WIZCHIP_READ_BUF(SUBR, subr, 4)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set local MAC address
+ * @param (uint8_t*)shar Pointer variable to set local MAC address. It should be allocated 6 bytes.
+ * @sa getSHAR()
+ */
+#define setSHAR(shar) \
+    WIZCHIP_WRITE_BUF(SHAR, shar, 6)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get local MAC address
+ * @param (uint8_t*)shar Pointer variable to get local MAC address. It should be allocated 6 bytes.
+ * @sa setSHAR()
+ */
+#define getSHAR(shar) \
+    WIZCHIP_READ_BUF(SHAR, shar, 6)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set local IP address
+ * @param (uint8_t*)sipr Pointer variable to set local IP address. It should be allocated 4 bytes.
+ * @sa getSIPR()
+ */
+#define setSIPR(sipr) \
+    WIZCHIP_WRITE_BUF(SIPR, sipr, 4)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get local IP address
+ * @param (uint8_t*)sipr Pointer variable to get local IP address. It should be allocated 4 bytes.
+ * @sa setSIPR()
+ */
+#define getSIPR(sipr) \
+    WIZCHIP_READ_BUF(SIPR, sipr, 4)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set INTLEVEL register
+ * @param (uint16_t)intlevel Value to set @ref INTLEVEL register.
+ * @sa getINTLEVEL()
+ */
+#define setINTLEVEL(intlevel)                                              \
+    {                                                                      \
+        WIZCHIP_WRITE(INTLEVEL, (uint8_t)(intlevel >> 8));                 \
+        WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(INTLEVEL, 1), (uint8_t)intlevel); \
+    }
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get INTLEVEL register
+ * @return uint16_t. Value of @ref INTLEVEL register.
+ * @sa setINTLEVEL()
+ */
+// M20150401 : Type explict declaration
+/*
+#define getINTLEVEL() \
+        ((WIZCHIP_READ(INTLEVEL) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(INTLEVEL,1)))
+*/
+#define getINTLEVEL() \
+    (((uint16_t)WIZCHIP_READ(INTLEVEL) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(INTLEVEL, 1)))
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set @ref IR register
+ * @param (uint8_t)ir Value to set @ref IR register.
+ * @sa getIR()
+ */
+#define setIR(ir) \
+    WIZCHIP_WRITE(IR, (ir & 0xF0))
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref IR register
+ * @return uint8_t. Value of @ref IR register.
+ * @sa setIR()
+ */
+#define getIR() \
+    (WIZCHIP_READ(IR) & 0xF0)
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set @ref _IMR_ register
+ * @param (uint8_t)imr Value to set @ref _IMR_ register.
+ * @sa getIMR()
+ */
+#define setIMR(imr) \
+    WIZCHIP_WRITE(_IMR_, imr)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref _IMR_ register
+ * @return uint8_t. Value of @ref _IMR_ register.
+ * @sa setIMR()
+ */
+#define getIMR() \
+    WIZCHIP_READ(_IMR_)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set @ref SIR register
+ * @param (uint8_t)sir Value to set @ref SIR register.
+ * @sa getSIR()
+ */
+#define setSIR(sir) \
+    WIZCHIP_WRITE(SIR, sir)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref SIR register
+ * @return uint8_t. Value of @ref SIR register.
+ * @sa setSIR()
+ */
+#define getSIR() \
+    WIZCHIP_READ(SIR)
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set @ref SIMR register
+ * @param (uint8_t)simr Value to set @ref SIMR register.
+ * @sa getSIMR()
+ */
+#define setSIMR(simr) \
+    WIZCHIP_WRITE(SIMR, simr)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref SIMR register
+ * @return uint8_t. Value of @ref SIMR register.
+ * @sa setSIMR()
+ */
+#define getSIMR() \
+    WIZCHIP_READ(SIMR)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set @ref _RTR_ register
+ * @param (uint16_t)rtr Value to set @ref _RTR_ register.
+ * @sa getRTR()
+ */
+#define setRTR(rtr)                                                \
+    {                                                              \
+        WIZCHIP_WRITE(_RTR_, (uint8_t)(rtr >> 8));                 \
+        WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(_RTR_, 1), (uint8_t)rtr); \
+    }
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref _RTR_ register
+ * @return uint16_t. Value of @ref _RTR_ register.
+ * @sa setRTR()
+ */
+// M20150401 : Type explict declaration
+/*
+#define getRTR() \
+        ((WIZCHIP_READ(_RTR_) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(_RTR_,1)))
+*/
+#define getRTR() \
+    (((uint16_t)WIZCHIP_READ(_RTR_) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(_RTR_, 1)))
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set @ref _RCR_ register
+ * @param (uint8_t)rcr Value to set @ref _RCR_ register.
+ * @sa getRCR()
+ */
+#define setRCR(rcr) \
+    WIZCHIP_WRITE(_RCR_, rcr)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref _RCR_ register
+ * @return uint8_t. Value of @ref _RCR_ register.
+ * @sa setRCR()
+ */
+#define getRCR() \
+    WIZCHIP_READ(_RCR_)
+
+//================================================== test done ===========================================================
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set @ref PTIMER register
+ * @param (uint8_t)ptimer Value to set @ref PTIMER register.
+ * @sa getPTIMER()
+ */
+#define setPTIMER(ptimer) \
+    WIZCHIP_WRITE(PTIMER, ptimer)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref PTIMER register
+ * @return uint8_t. Value of @ref PTIMER register.
+ * @sa setPTIMER()
+ */
+#define getPTIMER() \
+    WIZCHIP_READ(PTIMER)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set @ref PMAGIC register
+ * @param (uint8_t)pmagic Value to set @ref PMAGIC register.
+ * @sa getPMAGIC()
+ */
+#define setPMAGIC(pmagic) \
+    WIZCHIP_WRITE(PMAGIC, pmagic)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref PMAGIC register
+ * @return uint8_t. Value of @ref PMAGIC register.
+ * @sa setPMAGIC()
+ */
+#define getPMAGIC() \
+    WIZCHIP_READ(PMAGIC)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set @ref PHAR address
+ * @param (uint8_t*)phar Pointer variable to set PPP destination MAC register address. It should be allocated 6 bytes.
+ * @sa getPHAR()
+ */
+#define setPHAR(phar) \
+    WIZCHIP_WRITE_BUF(PHAR, phar, 6)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref PHAR address
+ * @param (uint8_t*)phar Pointer variable to PPP destination MAC register address. It should be allocated 6 bytes.
+ * @sa setPHAR()
+ */
+#define getPHAR(phar) \
+    WIZCHIP_READ_BUF(PHAR, phar, 6)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set @ref PSID register
+ * @param (uint16_t)psid Value to set @ref PSID register.
+ * @sa getPSID()
+ */
+#define setPSID(psid)                                              \
+    {                                                              \
+        WIZCHIP_WRITE(PSID, (uint8_t)(psid >> 8));                 \
+        WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(PSID, 1), (uint8_t)psid); \
+    }
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref PSID register
+ * @return uint16_t. Value of @ref PSID register.
+ * @sa setPSID()
+ */
+// uint16_t getPSID(void);
+// M20150401 : Type explict declaration
+/*
+#define getPSID() \
+        ((WIZCHIP_READ(PSID) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PSID,1)))
+*/
+#define getPSID() \
+    (((uint16_t)WIZCHIP_READ(PSID) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PSID, 1)))
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set @ref PMRU register
+ * @param (uint16_t)pmru Value to set @ref PMRU register.
+ * @sa getPMRU()
+ */
+#define setPMRU(pmru)                                              \
+    {                                                              \
+        WIZCHIP_WRITE(PMRU, (uint8_t)(pmru >> 8));                 \
+        WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(PMRU, 1), (uint8_t)pmru); \
+    }
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref PMRU register
+ * @return uint16_t. Value of @ref PMRU register.
+ * @sa setPMRU()
+ */
+// M20150401 : Type explict declaration
+/*
+#define getPMRU() \
+        ((WIZCHIP_READ(PMRU) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PMRU,1)))
+*/
+#define getPMRU() \
+    (((uint16_t)WIZCHIP_READ(PMRU) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PMRU, 1)))
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get unreachable IP address
+ * @param (uint8_t*)uipr Pointer variable to get unreachable IP address. It should be allocated 4 bytes.
+ */
+// M20150401 : Size Error of UIPR (6 -> 4)
+/*
+#define getUIPR(uipr) \
+        WIZCHIP_READ_BUF(UIPR,uipr,6)
+*/
+#define getUIPR(uipr) \
+    WIZCHIP_READ_BUF(UIPR, uipr, 4)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref UPORTR register
+ * @return uint16_t. Value of @ref UPORTR register.
+ */
+// M20150401 : Type explict declaration
+/*
+#define getUPORTR() \
+    ((WIZCHIP_READ(UPORTR) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(UPORTR,1)))
+*/
+#define getUPORTR() \
+    (((uint16_t)WIZCHIP_READ(UPORTR) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(UPORTR, 1)))
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Set @ref PHYCFGR register
+ * @param (uint8_t)phycfgr Value to set @ref PHYCFGR register.
+ * @sa getPHYCFGR()
+ */
+#define setPHYCFGR(phycfgr) \
+    WIZCHIP_WRITE(PHYCFGR, phycfgr)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref PHYCFGR register
+ * @return uint8_t. Value of @ref PHYCFGR register.
+ * @sa setPHYCFGR()
+ */
+#define getPHYCFGR() \
+    WIZCHIP_READ(PHYCFGR)
+
+/**
+ * @ingroup Common_register_access_function
+ * @brief Get @ref VERSIONR register
+ * @return uint8_t. Value of @ref VERSIONR register.
+ */
+#define getVERSIONR() \
+    WIZCHIP_READ(VERSIONR)
+
+/////////////////////////////////////
+
+///////////////////////////////////
+// Socket N register I/O function //
+///////////////////////////////////
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_MR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint8_t)mr Value to set @ref Sn_MR
+ * @sa getSn_MR()
+ */
+#define setSn_MR(sn, mr) \
+    WIZCHIP_WRITE(Sn_MR(sn), mr)
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_MR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint8_t. Value of @ref Sn_MR.
+ * @sa setSn_MR()
+ */
+#define getSn_MR(sn) \
+    WIZCHIP_READ(Sn_MR(sn))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_CR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint8_t)cr Value to set @ref Sn_CR
+ * @sa getSn_CR()
+ */
+#define setSn_CR(sn, cr) \
+    WIZCHIP_WRITE(Sn_CR(sn), cr)
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_CR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint8_t. Value of @ref Sn_CR.
+ * @sa setSn_CR()
+ */
+#define getSn_CR(sn) \
+    WIZCHIP_READ(Sn_CR(sn))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_IR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint8_t)ir Value to set @ref Sn_IR
+ * @sa getSn_IR()
+ */
+#define setSn_IR(sn, ir) \
+    WIZCHIP_WRITE(Sn_IR(sn), (ir & 0x1F))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_IR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint8_t. Value of @ref Sn_IR.
+ * @sa setSn_IR()
+ */
+#define getSn_IR(sn) \
+    (WIZCHIP_READ(Sn_IR(sn)) & 0x1F)
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_IMR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint8_t)imr Value to set @ref Sn_IMR
+ * @sa getSn_IMR()
+ */
+#define setSn_IMR(sn, imr) \
+    WIZCHIP_WRITE(Sn_IMR(sn), (imr & 0x1F))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_IMR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint8_t. Value of @ref Sn_IMR.
+ * @sa setSn_IMR()
+ */
+#define getSn_IMR(sn) \
+    (WIZCHIP_READ(Sn_IMR(sn)) & 0x1F)
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_SR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint8_t. Value of @ref Sn_SR.
+ */
+#define getSn_SR(sn) \
+    WIZCHIP_READ(Sn_SR(sn))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_PORT register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint16_t)port Value to set @ref Sn_PORT.
+ * @sa getSn_PORT()
+ */
+#define setSn_PORT(sn, port)                                              \
+    {                                                                     \
+        WIZCHIP_WRITE(Sn_PORT(sn), (uint8_t)(port >> 8));                 \
+        WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_PORT(sn), 1), (uint8_t)port); \
+    }
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_PORT register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint16_t. Value of @ref Sn_PORT.
+ * @sa setSn_PORT()
+ */
+// M20150401 : Type explict declaration
+/*
+#define getSn_PORT(sn) \
+        ((WIZCHIP_READ(Sn_PORT(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_PORT(sn),1)))
+*/
+#define getSn_PORT(sn) \
+    (((uint16_t)WIZCHIP_READ(Sn_PORT(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_PORT(sn), 1)))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_DHAR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint8_t*)dhar Pointer variable to set socket n destination hardware address. It should be allocated 6 bytes.
+ * @sa getSn_DHAR()
+ */
+#define setSn_DHAR(sn, dhar) \
+    WIZCHIP_WRITE_BUF(Sn_DHAR(sn), dhar, 6)
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_MR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint8_t*)dhar Pointer variable to get socket n destination hardware address. It should be allocated 6 bytes.
+ * @sa setSn_DHAR()
+ */
+#define getSn_DHAR(sn, dhar) \
+    WIZCHIP_READ_BUF(Sn_DHAR(sn), dhar, 6)
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_DIPR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint8_t*)dipr Pointer variable to set socket n destination IP address. It should be allocated 4 bytes.
+ * @sa getSn_DIPR()
+ */
+#define setSn_DIPR(sn, dipr) \
+    WIZCHIP_WRITE_BUF(Sn_DIPR(sn), dipr, 4)
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_DIPR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint8_t*)dipr Pointer variable to get socket n destination IP address. It should be allocated 4 bytes.
+ * @sa setSn_DIPR()
+ */
+#define getSn_DIPR(sn, dipr) \
+    WIZCHIP_READ_BUF(Sn_DIPR(sn), dipr, 4)
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_DPORT register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint16_t)dport Value to set @ref Sn_DPORT
+ * @sa getSn_DPORT()
+ */
+#define setSn_DPORT(sn, dport)                                              \
+    {                                                                       \
+        WIZCHIP_WRITE(Sn_DPORT(sn), (uint8_t)(dport >> 8));                 \
+        WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_DPORT(sn), 1), (uint8_t)dport); \
+    }
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_DPORT register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint16_t. Value of @ref Sn_DPORT.
+ * @sa setSn_DPORT()
+ */
+// M20150401 : Type explict declaration
+/*
+#define getSn_DPORT(sn) \
+        ((WIZCHIP_READ(Sn_DPORT(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_DPORT(sn),1)))
+*/
+#define getSn_DPORT(sn) \
+    (((uint16_t)WIZCHIP_READ(Sn_DPORT(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_DPORT(sn), 1)))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_MSSR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint16_t)mss Value to set @ref Sn_MSSR
+ * @sa setSn_MSSR()
+ */
+#define setSn_MSSR(sn, mss)                                              \
+    {                                                                    \
+        WIZCHIP_WRITE(Sn_MSSR(sn), (uint8_t)(mss >> 8));                 \
+        WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_MSSR(sn), 1), (uint8_t)mss); \
+    }
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_MSSR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint16_t. Value of @ref Sn_MSSR.
+ * @sa setSn_MSSR()
+ */
+// M20150401 : Type explict declaration
+/*
+#define getSn_MSSR(sn) \
+        ((WIZCHIP_READ(Sn_MSSR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_MSSR(sn),1)))
+*/
+#define getSn_MSSR(sn) \
+    (((uint16_t)WIZCHIP_READ(Sn_MSSR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_MSSR(sn), 1)))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_TOS register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint8_t)tos Value to set @ref Sn_TOS
+ * @sa getSn_TOS()
+ */
+#define setSn_TOS(sn, tos) \
+    WIZCHIP_WRITE(Sn_TOS(sn), tos)
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_TOS register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint8_t. Value of Sn_TOS.
+ * @sa setSn_TOS()
+ */
+#define getSn_TOS(sn) \
+    WIZCHIP_READ(Sn_TOS(sn))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_TTL register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint8_t)ttl Value to set @ref Sn_TTL
+ * @sa getSn_TTL()
+ */
+#define setSn_TTL(sn, ttl) \
+    WIZCHIP_WRITE(Sn_TTL(sn), ttl)
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_TTL register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint8_t. Value of @ref Sn_TTL.
+ * @sa setSn_TTL()
+ */
+#define getSn_TTL(sn) \
+    WIZCHIP_READ(Sn_TTL(sn))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_RXBUF_SIZE register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint8_t)rxbufsize Value to set @ref Sn_RXBUF_SIZE
+ * @sa getSn_RXBUF_SIZE()
+ */
+#define setSn_RXBUF_SIZE(sn, rxbufsize) \
+    WIZCHIP_WRITE(Sn_RXBUF_SIZE(sn), rxbufsize)
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_RXBUF_SIZE register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint8_t. Value of @ref Sn_RXBUF_SIZE.
+ * @sa setSn_RXBUF_SIZE()
+ */
+#define getSn_RXBUF_SIZE(sn) \
+    WIZCHIP_READ(Sn_RXBUF_SIZE(sn))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_TXBUF_SIZE register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint8_t)txbufsize Value to set @ref Sn_TXBUF_SIZE
+ * @sa getSn_TXBUF_SIZE()
+ */
+#define setSn_TXBUF_SIZE(sn, txbufsize) \
+    WIZCHIP_WRITE(Sn_TXBUF_SIZE(sn), txbufsize)
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_TXBUF_SIZE register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint8_t. Value of @ref Sn_TXBUF_SIZE.
+ * @sa setSn_TXBUF_SIZE()
+ */
+#define getSn_TXBUF_SIZE(sn) \
+    WIZCHIP_READ(Sn_TXBUF_SIZE(sn))
+
+    /**
+     * @ingroup Socket_register_access_function
+     * @brief Get @ref Sn_TX_FSR register
+     * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+     * @return uint16_t. Value of @ref Sn_TX_FSR.
+     */
+    uint16_t getSn_TX_FSR(uint8_t sn);
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_TX_RD register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint16_t. Value of @ref Sn_TX_RD.
+ */
+// M20150401 : Type explict declaration
+/*
+#define getSn_TX_RD(sn) \
+        ((WIZCHIP_READ(Sn_TX_RD(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_RD(sn),1)))
+*/
+#define getSn_TX_RD(sn) \
+    (((uint16_t)WIZCHIP_READ(Sn_TX_RD(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_RD(sn), 1)))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_TX_WR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint16_t)txwr Value to set @ref Sn_TX_WR
+ * @sa GetSn_TX_WR()
+ */
+#define setSn_TX_WR(sn, txwr)                                              \
+    {                                                                      \
+        WIZCHIP_WRITE(Sn_TX_WR(sn), (uint8_t)(txwr >> 8));                 \
+        WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_TX_WR(sn), 1), (uint8_t)txwr); \
+    }
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_TX_WR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint16_t. Value of @ref Sn_TX_WR.
+ * @sa setSn_TX_WR()
+ */
+// M20150401 : Type explict declaration
+/*
+#define getSn_TX_WR(sn) \
+        ((WIZCHIP_READ(Sn_TX_WR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_WR(sn),1)))
+*/
+#define getSn_TX_WR(sn) \
+    (((uint16_t)WIZCHIP_READ(Sn_TX_WR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_WR(sn), 1)))
+
+    /**
+     * @ingroup Socket_register_access_function
+     * @brief Get @ref Sn_RX_RSR register
+     * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+     * @return uint16_t. Value of @ref Sn_RX_RSR.
+     */
+    uint16_t getSn_RX_RSR(uint8_t sn);
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_RX_RD register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint16_t)rxrd Value to set @ref Sn_RX_RD
+ * @sa getSn_RX_RD()
+ */
+#define setSn_RX_RD(sn, rxrd)                                              \
+    {                                                                      \
+        WIZCHIP_WRITE(Sn_RX_RD(sn), (uint8_t)(rxrd >> 8));                 \
+        WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_RX_RD(sn), 1), (uint8_t)rxrd); \
+    }
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_RX_RD register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint16_t. Value of @ref Sn_RX_RD.
+ * @sa setSn_RX_RD()
+ */
+// M20150401 : Type explict declaration
+/*
+#define getSn_RX_RD(sn) \
+        ((WIZCHIP_READ(Sn_RX_RD(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RD(sn),1)))
+*/
+#define getSn_RX_RD(sn) \
+    (((uint16_t)WIZCHIP_READ(Sn_RX_RD(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RD(sn), 1)))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_RX_WR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint16_t. Value of @ref Sn_RX_WR.
+ */
+// M20150401 : Type explict declaration
+/*
+#define getSn_RX_WR(sn) \
+        ((WIZCHIP_READ(Sn_RX_WR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_WR(sn),1)))
+*/
+#define getSn_RX_WR(sn) \
+    (((uint16_t)WIZCHIP_READ(Sn_RX_WR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_WR(sn), 1)))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_FRAG register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint16_t)frag Value to set @ref Sn_FRAG
+ * @sa getSn_FRAD()
+ */
+#define setSn_FRAG(sn, frag)                                              \
+    {                                                                     \
+        WIZCHIP_WRITE(Sn_FRAG(sn), (uint8_t)(frag >> 8));                 \
+        WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_FRAG(sn), 1), (uint8_t)frag); \
+    }
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_FRAG register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint16_t. Value of @ref Sn_FRAG.
+ * @sa setSn_FRAG()
+ */
+// M20150401 : Type explict declaration
+/*
+#define getSn_FRAG(sn) \
+        ((WIZCHIP_READ(Sn_FRAG(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_FRAG(sn),1)))
+*/
+#define getSn_FRAG(sn) \
+    (((uint16_t)WIZCHIP_READ(Sn_FRAG(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_FRAG(sn), 1)))
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Set @ref Sn_KPALVTR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @param (uint8_t)kpalvt Value to set @ref Sn_KPALVTR
+ * @sa getSn_KPALVTR()
+ */
+#define setSn_KPALVTR(sn, kpalvt) \
+    WIZCHIP_WRITE(Sn_KPALVTR(sn), kpalvt)
+
+/**
+ * @ingroup Socket_register_access_function
+ * @brief Get @ref Sn_KPALVTR register
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint8_t. Value of @ref Sn_KPALVTR.
+ * @sa setSn_KPALVTR()
+ */
+#define getSn_KPALVTR(sn) \
+    WIZCHIP_READ(Sn_KPALVTR(sn))
+
+//////////////////////////////////////
+
+/////////////////////////////////////
+// Sn_TXBUF & Sn_RXBUF IO function //
+/////////////////////////////////////
+/**
+ * @brief Socket_register_access_function
+ * @brief Gets the max buffer size of socket sn passed as parameter.
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint16_t. Value of Socket n RX max buffer size.
+ */
+// M20150401 : Type explict declaration
+/*
+#define getSn_RxMAX(sn) \
+        (getSn_RXBUF_SIZE(sn) << 10)
+*/
+#define getSn_RxMAX(sn) \
+    (((uint16_t)getSn_RXBUF_SIZE(sn)) << 10)
+
+/**
+ * @brief Socket_register_access_function
+ * @brief Gets the max buffer size of socket sn passed as parameters.
+ * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+ * @return uint16_t. Value of Socket n TX max buffer size.
+ */
+// M20150401 : Type explict declaration
+/*
+#define getSn_TxMAX(sn) \
+        (getSn_TXBUF_SIZE(sn) << 10)
+*/
+#define getSn_TxMAX(sn) \
+    (((uint16_t)getSn_TXBUF_SIZE(sn)) << 10)
+
+    /**
+     * @ingroup Basic_IO_function
+     * @brief It copies data to internal TX memory
+     *
+     * @details This function reads the Tx write pointer register and after that,
+     * it copies the <i>wizdata(pointer buffer)</i> of the length of <i>len(variable)</i> bytes to internal TX memory
+     * and updates the Tx write pointer register.
+     * This function is being called by send() and sendto() function also.
+     *
+     * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+     * @param wizdata Pointer buffer to write data
+     * @param len Data length
+     * @sa wiz_recv_data()
+     */
+    void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len);
+
+    /**
+     * @ingroup Basic_IO_function
+     * @brief It copies data to your buffer from internal RX memory
+     *
+     * @details This function read the Rx read pointer register and after that,
+     * it copies the received data from internal RX memory
+     * to <i>wizdata(pointer variable)</i> of the length of <i>len(variable)</i> bytes.
+     * This function is being called by recv() also.
+     *
+     * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+     * @param wizdata Pointer buffer to read data
+     * @param len Data length
+     * @sa wiz_send_data()
+     */
+    void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len);
+
+    /**
+     * @ingroup Basic_IO_function
+     * @brief It discard the received data in RX memory.
+     * @details It discards the data of the length of <i>len(variable)</i> bytes in internal RX memory.
+     * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
+     * @param len Data length
+     */
+    void wiz_recv_ignore(uint8_t sn, uint16_t len);
+
+/// @cond DOXY_APPLY_CODE
+#endif
+    /// @endcond
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _W5500_H_

+ 887 - 0
ioLibrary/wizchip/wizchip_conf.c

@@ -0,0 +1,887 @@
+
+#include <stddef.h>
+//
+
+#include "wizchip_conf.h"
+
+/////////////
+// M20150401 : Remove ; in the default callback function such as wizchip_cris_enter(), wizchip_cs_select() and etc.
+/////////////
+
+/**
+ * @brief Default function to enable interrupt.
+ * @note This function help not to access wrong address. If you do not describe this function or register any functions,
+ * null function is called.
+ */
+// void 	  wizchip_cris_enter(void)           {};
+void wizchip_cris_enter(void) {}
+
+/**
+ * @brief Default function to disable interrupt.
+ * @note This function help not to access wrong address. If you do not describe this function or register any functions,
+ * null function is called.
+ */
+// void 	  wizchip_cris_exit(void)          {};
+void wizchip_cris_exit(void) {}
+
+/**
+ * @brief Default function to select chip.
+ * @note This function help not to access wrong address. If you do not describe this function or register any functions,
+ * null function is called.
+ */
+// void 	wizchip_cs_select(void)            {};
+void wizchip_cs_select(void) {}
+
+/**
+ * @brief Default function to deselect chip.
+ * @note This function help not to access wrong address. If you do not describe this function or register any functions,
+ * null function is called.
+ */
+// void 	wizchip_cs_deselect(void)          {};
+void wizchip_cs_deselect(void) {}
+
+/**
+ * @brief Default function to read in direct or indirect interface.
+ * @note This function help not to access wrong address. If you do not describe this function or register any functions,
+ * null function is called.
+ */
+// M20150601 : Rename the function for integrating with W5300
+// uint8_t wizchip_bus_readbyte(uint32_t AddrSel) { return * ((volatile uint8_t *)((ptrdiff_t) AddrSel)); }
+iodata_t wizchip_bus_readdata(uint32_t AddrSel) { return *((volatile iodata_t *)((ptrdiff_t)AddrSel)); }
+
+/**
+ * @brief Default function to write in direct or indirect interface.
+ * @note This function help not to access wrong address. If you do not describe this function or register any functions,
+ * null function is called.
+ */
+// M20150601 : Rename the function for integrating with W5300
+// void 	wizchip_bus_writebyte(uint32_t AddrSel, uint8_t wb)  { *((volatile uint8_t*)((ptrdiff_t)AddrSel)) = wb; }
+void wizchip_bus_writedata(uint32_t AddrSel, iodata_t wb) { *((volatile iodata_t *)((ptrdiff_t)AddrSel)) = wb; }
+
+/**
+ * @brief Default function to read in SPI interface.
+ * @note This function help not to access wrong address. If you do not describe this function or register any functions,
+ * null function is called.
+ */
+// uint8_t wizchip_spi_readbyte(void)        {return 0;};
+uint8_t wizchip_spi_readbyte(void) { return 0; }
+
+/**
+ * @brief Default function to write in SPI interface.
+ * @note This function help not to access wrong address. If you do not describe this function or register any functions,
+ * null function is called.
+ */
+// void 	wizchip_spi_writebyte(uint8_t wb) {};
+void wizchip_spi_writebyte(uint8_t wb) {}
+
+/**
+ * @brief Default function to burst read in SPI interface.
+ * @note This function help not to access wrong address. If you do not describe this function or register any functions,
+ * null function is called.
+ */
+// void 	wizchip_spi_readburst(uint8_t* pBuf, uint16_t len) 	{};
+void wizchip_spi_readburst(uint8_t *pBuf, uint16_t len) {}
+
+/**
+ * @brief Default function to burst write in SPI interface.
+ * @note This function help not to access wrong address. If you do not describe this function or register any functions,
+ * null function is called.
+ */
+// void 	wizchip_spi_writeburst(uint8_t* pBuf, uint16_t len) {};
+void wizchip_spi_writeburst(uint8_t *pBuf, uint16_t len) {}
+
+/**
+ * @\ref _WIZCHIP instance
+ */
+//
+// M20150401 : For a compiler didnot support a member of structure
+//            Replace the assignment of struct members with the assingment of array
+//
+/*
+_WIZCHIP  WIZCHIP =
+      {
+      .id                  = _WIZCHIP_ID_,
+      .if_mode             = _WIZCHIP_IO_MODE_,
+      .CRIS._enter         = wizchip_cris_enter,
+      .CRIS._exit          = wizchip_cris_exit,
+      .CS._select          = wizchip_cs_select,
+      .CS._deselect        = wizchip_cs_deselect,
+      .IF.BUS._read_byte   = wizchip_bus_readbyte,
+      .IF.BUS._write_byte  = wizchip_bus_writebyte
+//    .IF.SPI._read_byte   = wizchip_spi_readbyte,
+//    .IF.SPI._write_byte  = wizchip_spi_writebyte
+      };
+*/
+_WIZCHIP WIZCHIP =
+    {
+        _WIZCHIP_IO_MODE_,
+        _WIZCHIP_ID_,
+        {wizchip_cris_enter,
+         wizchip_cris_exit},
+        {wizchip_cs_select,
+         wizchip_cs_deselect},
+        {
+            {// M20150601 : Rename the function
+             // wizchip_bus_readbyte,
+             // wizchip_bus_writebyte
+             wizchip_bus_readdata,
+             wizchip_bus_writedata},
+
+        }};
+
+static uint8_t _DNS_[4]; // DNS server ip address
+static dhcp_mode _DHCP_; // DHCP mode
+
+void reg_wizchip_cris_cbfunc(void (*cris_en)(void), void (*cris_ex)(void))
+{
+    if (!cris_en || !cris_ex)
+    {
+        WIZCHIP.CRIS._enter = wizchip_cris_enter;
+        WIZCHIP.CRIS._exit = wizchip_cris_exit;
+    }
+    else
+    {
+        WIZCHIP.CRIS._enter = cris_en;
+        WIZCHIP.CRIS._exit = cris_ex;
+    }
+}
+
+void reg_wizchip_cs_cbfunc(void (*cs_sel)(void), void (*cs_desel)(void))
+{
+    if (!cs_sel || !cs_desel)
+    {
+        WIZCHIP.CS._select = wizchip_cs_select;
+        WIZCHIP.CS._deselect = wizchip_cs_deselect;
+    }
+    else
+    {
+        WIZCHIP.CS._select = cs_sel;
+        WIZCHIP.CS._deselect = cs_desel;
+    }
+}
+
+// M20150515 : For integrating with W5300
+// void reg_wizchip_bus_cbfunc(uint8_t(*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, uint8_t wb))
+void reg_wizchip_bus_cbfunc(iodata_t (*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, iodata_t wb))
+{
+    while (!(WIZCHIP.if_mode & _WIZCHIP_IO_MODE_BUS_))
+        ;
+    // M20150601 : Rename call back function for integrating with W5300
+    /*
+    if(!bus_rb || !bus_wb)
+    {
+       WIZCHIP.IF.BUS._read_byte   = wizchip_bus_readbyte;
+       WIZCHIP.IF.BUS._write_byte  = wizchip_bus_writebyte;
+    }
+    else
+    {
+       WIZCHIP.IF.BUS._read_byte   = bus_rb;
+       WIZCHIP.IF.BUS._write_byte  = bus_wb;
+    }
+    */
+    if (!bus_rb || !bus_wb)
+    {
+        WIZCHIP.IF.BUS._read_data = wizchip_bus_readdata;
+        WIZCHIP.IF.BUS._write_data = wizchip_bus_writedata;
+    }
+    else
+    {
+        WIZCHIP.IF.BUS._read_data = bus_rb;
+        WIZCHIP.IF.BUS._write_data = bus_wb;
+    }
+}
+
+void reg_wizchip_spi_cbfunc(uint8_t (*spi_rb)(void), void (*spi_wb)(uint8_t wb))
+{
+    while (!(WIZCHIP.if_mode & _WIZCHIP_IO_MODE_SPI_))
+        ;
+
+    if (!spi_rb || !spi_wb)
+    {
+        WIZCHIP.IF.SPI._read_byte = wizchip_spi_readbyte;
+        WIZCHIP.IF.SPI._write_byte = wizchip_spi_writebyte;
+    }
+    else
+    {
+        WIZCHIP.IF.SPI._read_byte = spi_rb;
+        WIZCHIP.IF.SPI._write_byte = spi_wb;
+    }
+}
+
+// 20140626 Eric Added for SPI burst operations
+void reg_wizchip_spiburst_cbfunc(void (*spi_rb)(uint8_t *pBuf, uint16_t len), void (*spi_wb)(uint8_t *pBuf, uint16_t len))
+{
+    while (!(WIZCHIP.if_mode & _WIZCHIP_IO_MODE_SPI_))
+        ;
+
+    if (!spi_rb || !spi_wb)
+    {
+        WIZCHIP.IF.SPI._read_burst = wizchip_spi_readburst;
+        WIZCHIP.IF.SPI._write_burst = wizchip_spi_writeburst;
+    }
+    else
+    {
+        WIZCHIP.IF.SPI._read_burst = spi_rb;
+        WIZCHIP.IF.SPI._write_burst = spi_wb;
+    }
+}
+
+int8_t ctlwizchip(ctlwizchip_type cwtype, void *arg)
+{
+#if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5200 || _WIZCHIP_ == W5500
+    uint8_t tmp = 0;
+#endif
+    uint8_t *ptmp[2] = {0, 0};
+    switch (cwtype)
+    {
+    case CW_RESET_WIZCHIP:
+        wizchip_sw_reset();
+        break;
+    case CW_INIT_WIZCHIP:
+        if (arg != 0)
+        {
+            ptmp[0] = (uint8_t *)arg;
+            ptmp[1] = ptmp[0] + _WIZCHIP_SOCK_NUM_;
+        }
+        return wizchip_init(ptmp[0], ptmp[1]);
+    case CW_CLR_INTERRUPT:
+        wizchip_clrinterrupt(*((intr_kind *)arg));
+        break;
+    case CW_GET_INTERRUPT:
+        *((intr_kind *)arg) = wizchip_getinterrupt();
+        break;
+    case CW_SET_INTRMASK:
+        wizchip_setinterruptmask(*((intr_kind *)arg));
+        break;
+    case CW_GET_INTRMASK:
+        *((intr_kind *)arg) = wizchip_getinterruptmask();
+        break;
+// M20150601 : This can be supported by W5200, W5500
+// #if _WIZCHIP_ > W5100
+#if (_WIZCHIP_ == W5200 || _WIZCHIP_ == W5500)
+    case CW_SET_INTRTIME:
+        setINTLEVEL(*(uint16_t *)arg);
+        break;
+    case CW_GET_INTRTIME:
+        *(uint16_t *)arg = getINTLEVEL();
+        break;
+#endif
+    case CW_GET_ID:
+        ((uint8_t *)arg)[0] = WIZCHIP.id[0];
+        ((uint8_t *)arg)[1] = WIZCHIP.id[1];
+        ((uint8_t *)arg)[2] = WIZCHIP.id[2];
+        ((uint8_t *)arg)[3] = WIZCHIP.id[3];
+        ((uint8_t *)arg)[4] = WIZCHIP.id[4];
+        ((uint8_t *)arg)[5] = WIZCHIP.id[5];
+        ((uint8_t *)arg)[6] = 0;
+        break;
+#if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5500
+    case CW_RESET_PHY:
+        wizphy_reset();
+        break;
+    case CW_SET_PHYCONF:
+        wizphy_setphyconf((wiz_PhyConf *)arg);
+        break;
+    case CW_GET_PHYCONF:
+        wizphy_getphyconf((wiz_PhyConf *)arg);
+        break;
+    case CW_GET_PHYSTATUS:
+        break;
+    case CW_SET_PHYPOWMODE:
+        return wizphy_setphypmode(*(uint8_t *)arg);
+#endif
+#if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5200 || _WIZCHIP_ == W5500
+    case CW_GET_PHYPOWMODE:
+        tmp = wizphy_getphypmode();
+        if ((int8_t)tmp == -1)
+            return -1;
+        *(uint8_t *)arg = tmp;
+        break;
+    case CW_GET_PHYLINK:
+        tmp = wizphy_getphylink();
+        if ((int8_t)tmp == -1)
+            return -1;
+        *(uint8_t *)arg = tmp;
+        break;
+#endif
+    default:
+        return -1;
+    }
+    return 0;
+}
+
+int8_t ctlnetwork(ctlnetwork_type cntype, void *arg)
+{
+
+    switch (cntype)
+    {
+    case CN_SET_NETINFO:
+        wizchip_setnetinfo((wiz_NetInfo *)arg);
+        break;
+    case CN_GET_NETINFO:
+        wizchip_getnetinfo((wiz_NetInfo *)arg);
+        break;
+    case CN_SET_NETMODE:
+        return wizchip_setnetmode(*(netmode_type *)arg);
+    case CN_GET_NETMODE:
+        *(netmode_type *)arg = wizchip_getnetmode();
+        break;
+    case CN_SET_TIMEOUT:
+        wizchip_settimeout((wiz_NetTimeout *)arg);
+        break;
+    case CN_GET_TIMEOUT:
+        wizchip_gettimeout((wiz_NetTimeout *)arg);
+        break;
+    default:
+        return -1;
+    }
+    return 0;
+}
+
+void wizchip_sw_reset(void)
+{
+    uint8_t gw[4], sn[4], sip[4];
+    uint8_t mac[6];
+// A20150601
+#if _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_
+    uint16_t mr = (uint16_t)getMR();
+    setMR(mr | MR_IND);
+#endif
+    //
+    getSHAR(mac);
+    getGAR(gw);
+    getSUBR(sn);
+    getSIPR(sip);
+    setMR(MR_RST);
+    getMR(); // for delay
+// A2015051 : For indirect bus mode
+#if _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_
+    setMR(mr | MR_IND);
+#endif
+    //
+    setSHAR(mac);
+    setGAR(gw);
+    setSUBR(sn);
+    setSIPR(sip);
+}
+
+int8_t wizchip_init(uint8_t *txsize, uint8_t *rxsize)
+{
+    int8_t i;
+#if _WIZCHIP_ < W5200
+    int8_t j;
+#endif
+    int8_t tmp = 0;
+    wizchip_sw_reset();
+    if (txsize)
+    {
+        tmp = 0;
+// M20150601 : For integrating with W5300
+#if _WIZCHIP_ == W5300
+        for (i = 0; i < _WIZCHIP_SOCK_NUM_; i++)
+        {
+            if (txsize[i] >= 64)
+                return -1; // No use 64KB even if W5300 support max 64KB memory allocation
+            tmp += txsize[i];
+            if (tmp > 128)
+                return -1;
+        }
+        if (tmp % 8)
+            return -1;
+#else
+        for (i = 0; i < _WIZCHIP_SOCK_NUM_; i++)
+        {
+            tmp += txsize[i];
+
+#if _WIZCHIP_ < W5200 // 2016.10.28 peter add condition for w5100 and w5100s
+            if (tmp > 8)
+                return -1;
+#else
+            if (tmp > 16)
+                return -1;
+#endif
+        }
+        for (i = 0; i < _WIZCHIP_SOCK_NUM_; i++)
+        {
+#if _WIZCHIP_ < W5200 // 2016.10.28 peter add condition for w5100
+            j = 0;
+            while ((txsize[i] >> j != 1) && (txsize[i] != 0))
+            {
+                j++;
+            }
+            setSn_TXBUF_SIZE(i, j);
+#else
+            setSn_TXBUF_SIZE(i, txsize[i]);
+#endif
+        }
+
+#endif
+    }
+
+    if (rxsize)
+    {
+        tmp = 0;
+#if _WIZCHIP_ == W5300
+        for (i = 0; i < _WIZCHIP_SOCK_NUM_; i++)
+        {
+            if (rxsize[i] >= 64)
+                return -1; // No use 64KB even if W5300 support max 64KB memory allocation
+            tmp += rxsize[i];
+            if (tmp > 128)
+                return -1;
+        }
+        if (tmp % 8)
+            return -1;
+#else
+        for (i = 0; i < _WIZCHIP_SOCK_NUM_; i++)
+        {
+            tmp += rxsize[i];
+#if _WIZCHIP_ < W5200 // 2016.10.28 peter add condition for w5100 and w5100s
+            if (tmp > 8)
+                return -1;
+#else
+            if (tmp > 16)
+                return -1;
+#endif
+        }
+
+        for (i = 0; i < _WIZCHIP_SOCK_NUM_; i++)
+        {
+#if _WIZCHIP_ < W5200 // add condition for w5100
+            j = 0;
+            while ((rxsize[i] >> j != 1) && (txsize[i] != 0))
+            {
+                j++;
+            }
+            setSn_RXBUF_SIZE(i, j);
+#else
+            setSn_RXBUF_SIZE(i, rxsize[i]);
+#endif
+        }
+#endif
+    }
+    return 0;
+}
+
+void wizchip_clrinterrupt(intr_kind intr)
+{
+    uint8_t ir = (uint8_t)intr;
+    uint8_t sir = (uint8_t)((uint16_t)intr >> 8);
+#if _WIZCHIP_ < W5500
+    ir |= (1 << 4); // IK_WOL
+#endif
+#if _WIZCHIP_ == W5200
+    ir |= (1 << 6);
+#endif
+
+#if _WIZCHIP_ < W5200
+    sir &= 0x0F;
+#endif
+
+#if _WIZCHIP_ <= W5100S
+    ir |= sir;
+    setIR(ir);
+// A20150601 : For integrating with W5300
+#elif _WIZCHIP_ == W5300
+    setIR(((((uint16_t)ir) << 8) | (((uint16_t)sir) & 0x00FF)));
+#else
+    setIR(ir);
+    // M20200227 : For clear
+    // setSIR(sir);
+    for (ir = 0; ir < 8; ir++)
+    {
+        if (sir & (0x01 << ir))
+            setSn_IR(ir, 0xff);
+    }
+
+#endif
+}
+
+intr_kind wizchip_getinterrupt(void)
+{
+    uint8_t ir = 0;
+    uint8_t sir = 0;
+    uint16_t ret = 0;
+#if _WIZCHIP_ <= W5100S
+    ir = getIR();
+    sir = ir & 0x0F;
+// A20150601 : For integrating with W5300
+#elif _WIZCHIP_ == W5300
+    ret = getIR();
+    ir = (uint8_t)(ret >> 8);
+    sir = (uint8_t)ret;
+#else
+    ir = getIR();
+    sir = getSIR();
+#endif
+
+// M20150601 : For Integrating with W5300
+// #if _WIZCHIP_ < W5500
+#if _WIZCHIP_ < W5200
+    ir &= ~(1 << 4); // IK_WOL
+#endif
+#if _WIZCHIP_ == W5200
+    ir &= ~(1 << 6);
+#endif
+    ret = sir;
+    ret = (ret << 8) + ir;
+    return (intr_kind)ret;
+}
+
+void wizchip_setinterruptmask(intr_kind intr)
+{
+    uint8_t imr = (uint8_t)intr;
+    uint8_t simr = (uint8_t)((uint16_t)intr >> 8);
+#if _WIZCHIP_ < W5500
+    imr &= ~(1 << 4); // IK_WOL
+#endif
+#if _WIZCHIP_ == W5200
+    imr &= ~(1 << 6);
+#endif
+
+#if _WIZCHIP_ < W5200
+    simr &= 0x0F;
+    imr |= simr;
+    setIMR(imr);
+// A20150601 : For integrating with W5300
+#elif _WIZCHIP_ == W5300
+    setIMR(((((uint16_t)imr) << 8) | (((uint16_t)simr) & 0x00FF)));
+#else
+    setIMR(imr);
+    setSIMR(simr);
+#endif
+}
+
+intr_kind wizchip_getinterruptmask(void)
+{
+    uint8_t imr = 0;
+    uint8_t simr = 0;
+    uint16_t ret = 0;
+#if _WIZCHIP_ < W5200
+    imr = getIMR();
+    simr = imr & 0x0F;
+// A20150601 : For integrating with W5300
+#elif _WIZCHIP_ == W5300
+    ret = getIMR();
+    imr = (uint8_t)(ret >> 8);
+    simr = (uint8_t)ret;
+#else
+    imr = getIMR();
+    simr = getSIMR();
+#endif
+
+#if _WIZCHIP_ < W5500
+    imr &= ~(1 << 4); // IK_WOL
+#endif
+#if _WIZCHIP_ == W5200
+    imr &= ~(1 << 6); // IK_DEST_UNREACH
+#endif
+    ret = simr;
+    ret = (ret << 8) + imr;
+    return (intr_kind)ret;
+}
+
+int8_t wizphy_getphylink(void)
+{
+    int8_t tmp = PHY_LINK_OFF;
+#if _WIZCHIP_ == W5100S
+    if (getPHYSR() & PHYSR_LNK)
+        tmp = PHY_LINK_ON;
+#elif _WIZCHIP_ == W5200
+    if (getPHYSTATUS() & PHYSTATUS_LINK)
+        tmp = PHY_LINK_ON;
+#elif _WIZCHIP_ == W5500
+    if (getPHYCFGR() & PHYCFGR_LNK_ON)
+        tmp = PHY_LINK_ON;
+
+#else
+    tmp = -1;
+#endif
+    return tmp;
+}
+
+#if _WIZCHIP_ > W5100
+
+int8_t wizphy_getphypmode(void)
+{
+    int8_t tmp = 0;
+#if _WIZCHIP_ == W5200
+    if (getPHYSTATUS() & PHYSTATUS_POWERDOWN)
+        tmp = PHY_POWER_DOWN;
+    else
+        tmp = PHY_POWER_NORM;
+#elif _WIZCHIP_ == 5500
+    if ((getPHYCFGR() & PHYCFGR_OPMDC_ALLA) == PHYCFGR_OPMDC_PDOWN)
+        tmp = PHY_POWER_DOWN;
+    else
+        tmp = PHY_POWER_NORM;
+#else
+    tmp = -1;
+#endif
+    return tmp;
+}
+#endif
+
+#if _WIZCHIP_ == W5100S
+void wizphy_reset(void)
+{
+    uint16_t tmp = wiz_mdio_read(PHYMDIO_BMCR);
+    tmp |= BMCR_RESET;
+    wiz_mdio_write(PHYMDIO_BMCR, tmp);
+    while (wiz_mdio_read(PHYMDIO_BMCR) & BMCR_RESET)
+    {
+    }
+}
+
+void wizphy_setphyconf(wiz_PhyConf *phyconf)
+{
+    uint16_t tmp = wiz_mdio_read(PHYMDIO_BMCR);
+    if (phyconf->mode == PHY_MODE_AUTONEGO)
+        tmp |= BMCR_AUTONEGO;
+    else
+    {
+        tmp &= ~BMCR_AUTONEGO;
+        if (phyconf->duplex == PHY_DUPLEX_FULL)
+        {
+            tmp |= BMCR_DUP;
+        }
+        else
+        {
+            tmp &= ~BMCR_DUP;
+        }
+        if (phyconf->speed == PHY_SPEED_100)
+        {
+            tmp |= BMCR_SPEED;
+        }
+        else
+        {
+            tmp &= ~BMCR_SPEED;
+        }
+    }
+    wiz_mdio_write(PHYMDIO_BMCR, tmp);
+}
+
+void wizphy_getphyconf(wiz_PhyConf *phyconf)
+{
+    uint16_t tmp = 0;
+    tmp = wiz_mdio_read(PHYMDIO_BMCR);
+    phyconf->by = PHY_CONFBY_SW;
+    if (tmp & BMCR_AUTONEGO)
+    {
+        phyconf->mode = PHY_MODE_AUTONEGO;
+    }
+    else
+    {
+        phyconf->mode = PHY_MODE_MANUAL;
+        if (tmp & BMCR_DUP)
+            phyconf->duplex = PHY_DUPLEX_FULL;
+        else
+            phyconf->duplex = PHY_DUPLEX_HALF;
+        if (tmp & BMCR_SPEED)
+            phyconf->speed = PHY_SPEED_100;
+        else
+            phyconf->speed = PHY_SPEED_10;
+    }
+}
+
+int8_t wizphy_setphypmode(uint8_t pmode)
+{
+    uint16_t tmp = 0;
+    tmp = wiz_mdio_read(PHYMDIO_BMCR);
+    if (pmode == PHY_POWER_DOWN)
+    {
+        tmp |= BMCR_PWDN;
+    }
+    else
+    {
+        tmp &= ~BMCR_PWDN;
+    }
+    wiz_mdio_write(PHYMDIO_BMCR, tmp);
+    tmp = wiz_mdio_read(PHYMDIO_BMCR);
+    if (pmode == PHY_POWER_DOWN)
+    {
+        if (tmp & BMCR_PWDN)
+            return 0;
+    }
+    else
+    {
+        if ((tmp & BMCR_PWDN) != BMCR_PWDN)
+            return 0;
+    }
+    return -1;
+}
+
+#endif
+#if _WIZCHIP_ == W5500
+void wizphy_reset(void)
+{
+    uint8_t tmp = getPHYCFGR();
+    tmp &= PHYCFGR_RST;
+    setPHYCFGR(tmp);
+    tmp = getPHYCFGR();
+    tmp |= ~PHYCFGR_RST;
+    setPHYCFGR(tmp);
+}
+
+void wizphy_setphyconf(wiz_PhyConf *phyconf)
+{
+    uint8_t tmp = 0;
+    if (phyconf->by == PHY_CONFBY_SW)
+        tmp |= PHYCFGR_OPMD;
+    else
+        tmp &= ~PHYCFGR_OPMD;
+    if (phyconf->mode == PHY_MODE_AUTONEGO)
+        tmp |= PHYCFGR_OPMDC_ALLA;
+    else
+    {
+        if (phyconf->duplex == PHY_DUPLEX_FULL)
+        {
+            if (phyconf->speed == PHY_SPEED_100)
+                tmp |= PHYCFGR_OPMDC_100F;
+            else
+                tmp |= PHYCFGR_OPMDC_10F;
+        }
+        else
+        {
+            if (phyconf->speed == PHY_SPEED_100)
+                tmp |= PHYCFGR_OPMDC_100H;
+            else
+                tmp |= PHYCFGR_OPMDC_10H;
+        }
+    }
+    setPHYCFGR(tmp);
+    wizphy_reset();
+}
+
+void wizphy_getphyconf(wiz_PhyConf *phyconf)
+{
+    uint8_t tmp = 0;
+    tmp = getPHYCFGR();
+    phyconf->by = (tmp & PHYCFGR_OPMD) ? PHY_CONFBY_SW : PHY_CONFBY_HW;
+    switch (tmp & PHYCFGR_OPMDC_ALLA)
+    {
+    case PHYCFGR_OPMDC_ALLA:
+    case PHYCFGR_OPMDC_100FA:
+        phyconf->mode = PHY_MODE_AUTONEGO;
+        break;
+    default:
+        phyconf->mode = PHY_MODE_MANUAL;
+        break;
+    }
+    switch (tmp & PHYCFGR_OPMDC_ALLA)
+    {
+    case PHYCFGR_OPMDC_100FA:
+    case PHYCFGR_OPMDC_100F:
+    case PHYCFGR_OPMDC_100H:
+        phyconf->speed = PHY_SPEED_100;
+        break;
+    default:
+        phyconf->speed = PHY_SPEED_10;
+        break;
+    }
+    switch (tmp & PHYCFGR_OPMDC_ALLA)
+    {
+    case PHYCFGR_OPMDC_100FA:
+    case PHYCFGR_OPMDC_100F:
+    case PHYCFGR_OPMDC_10F:
+        phyconf->duplex = PHY_DUPLEX_FULL;
+        break;
+    default:
+        phyconf->duplex = PHY_DUPLEX_HALF;
+        break;
+    }
+}
+
+void wizphy_getphystat(wiz_PhyConf *phyconf)
+{
+    uint8_t tmp = getPHYCFGR();
+    phyconf->duplex = (tmp & PHYCFGR_DPX_FULL) ? PHY_DUPLEX_FULL : PHY_DUPLEX_HALF;
+    phyconf->speed = (tmp & PHYCFGR_SPD_100) ? PHY_SPEED_100 : PHY_SPEED_10;
+}
+
+int8_t wizphy_setphypmode(uint8_t pmode)
+{
+    uint8_t tmp = 0;
+    tmp = getPHYCFGR();
+    if ((tmp & PHYCFGR_OPMD) == 0)
+        return -1;
+    tmp &= ~PHYCFGR_OPMDC_ALLA;
+    if (pmode == PHY_POWER_DOWN)
+        tmp |= PHYCFGR_OPMDC_PDOWN;
+    else
+        tmp |= PHYCFGR_OPMDC_ALLA;
+    setPHYCFGR(tmp);
+    wizphy_reset();
+    tmp = getPHYCFGR();
+    if (pmode == PHY_POWER_DOWN)
+    {
+        if (tmp & PHYCFGR_OPMDC_PDOWN)
+            return 0;
+    }
+    else
+    {
+        if (tmp & PHYCFGR_OPMDC_ALLA)
+            return 0;
+    }
+    return -1;
+}
+#endif
+
+void wizchip_setnetinfo(wiz_NetInfo *pnetinfo)
+{
+    setSHAR(pnetinfo->mac);
+    setGAR(pnetinfo->gw);
+    setSUBR(pnetinfo->sn);
+    setSIPR(pnetinfo->ip);
+    _DNS_[0] = pnetinfo->dns[0];
+    _DNS_[1] = pnetinfo->dns[1];
+    _DNS_[2] = pnetinfo->dns[2];
+    _DNS_[3] = pnetinfo->dns[3];
+    _DHCP_ = pnetinfo->dhcp;
+}
+
+void wizchip_getnetinfo(wiz_NetInfo *pnetinfo)
+{
+    getSHAR(pnetinfo->mac);
+    getGAR(pnetinfo->gw);
+    getSUBR(pnetinfo->sn);
+    getSIPR(pnetinfo->ip);
+    pnetinfo->dns[0] = _DNS_[0];
+    pnetinfo->dns[1] = _DNS_[1];
+    pnetinfo->dns[2] = _DNS_[2];
+    pnetinfo->dns[3] = _DNS_[3];
+    pnetinfo->dhcp = _DHCP_;
+}
+
+int8_t wizchip_setnetmode(netmode_type netmode)
+{
+    uint8_t tmp = 0;
+#if _WIZCHIP_ != W5500
+    if (netmode & ~(NM_WAKEONLAN | NM_PPPOE | NM_PINGBLOCK))
+        return -1;
+#else
+    if (netmode & ~(NM_WAKEONLAN | NM_PPPOE | NM_PINGBLOCK | NM_FORCEARP))
+        return -1;
+#endif
+    tmp = getMR();
+    tmp |= (uint8_t)netmode;
+    setMR(tmp);
+    return 0;
+}
+
+netmode_type wizchip_getnetmode(void)
+{
+    return (netmode_type)getMR();
+}
+
+void wizchip_settimeout(wiz_NetTimeout *nettime)
+{
+    setRCR(nettime->retry_cnt);
+    setRTR(nettime->time_100us);
+}
+
+void wizchip_gettimeout(wiz_NetTimeout *nettime)
+{
+    nettime->retry_cnt = getRCR();
+    nettime->time_100us = getRTR();
+}

+ 658 - 0
ioLibrary/wizchip/wizchip_conf.h

@@ -0,0 +1,658 @@
+//*****************************************************************************
+//
+//! \file wizchip_conf.h
+//! \brief WIZCHIP Config Header File.
+//! \version 1.0.0
+//! \date 2013/10/21
+//! \par  Revision history
+//!       <2015/02/05> Notice
+//!        The version history is not updated after this point.
+//!        Download the latest version directly from GitHub. Please visit the our GitHub repository for ioLibrary.
+//!        >> https://github.com/Wiznet/ioLibrary_Driver
+//!       <2013/10/21> 1st Release
+//! \author MidnightCow
+//! \copyright
+//!
+//! Copyright (c)  2013, WIZnet Co., LTD.
+//! All rights reserved.
+//!
+//! Redistribution and use in source and binary forms, with or without
+//! modification, are permitted provided that the following conditions
+//! are met:
+//!
+//!     * Redistributions of source code must retain the above copyright
+//! notice, this list of conditions and the following disclaimer.
+//!     * Redistributions in binary form must reproduce the above copyright
+//! notice, this list of conditions and the following disclaimer in the
+//! documentation and/or other materials provided with the distribution.
+//!     * Neither the name of the <ORGANIZATION> nor the names of its
+//! contributors may be used to endorse or promote products derived
+//! from this software without specific prior written permission.
+//!
+//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+//! THE POSSIBILITY OF SUCH DAMAGE.
+//
+//*****************************************************************************
+
+/**
+ * @defgroup extra_functions 2. WIZnet Extra Functions
+ *
+ * @brief These functions is optional function. It could be replaced at WIZCHIP I/O function because they were made by WIZCHIP I/O functions.
+ * @details There are functions of configuring WIZCHIP, network, interrupt, phy, network information and timer. \n
+ *
+ */
+
+#ifndef _WIZCHIP_CONF_H_
+#define _WIZCHIP_CONF_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+    /**
+     * @brief Select WIZCHIP.
+     * @todo You should select one, \b W5100, \b W5100S, \b W5200, \b W5300, \b W5500 or etc. \n\n
+     *       ex> <code> #define \_WIZCHIP_      W5500 </code>
+     */
+
+#define W5100 5100
+#define W5100S 5100 + 5
+#define W5200 5200
+#define W5300 5300
+#define W5500 5500
+
+#ifndef _WIZCHIP_
+#define _WIZCHIP_ W5500 // W5100, W5100S, W5200, W5300, W5500
+#endif
+
+#define _WIZCHIP_IO_MODE_NONE_ 0x0000
+#define _WIZCHIP_IO_MODE_BUS_ 0x0100 /**< Bus interface mode */
+#define _WIZCHIP_IO_MODE_SPI_ 0x0200 /**< SPI interface mode */
+    // #define _WIZCHIP_IO_MODE_IIC_          0x0400
+    // #define _WIZCHIP_IO_MODE_SDIO_         0x0800
+    //  Add to
+    //
+
+#define _WIZCHIP_IO_MODE_BUS_DIR_ (_WIZCHIP_IO_MODE_BUS_ + 1)   /**< BUS interface mode for direct  */
+#define _WIZCHIP_IO_MODE_BUS_INDIR_ (_WIZCHIP_IO_MODE_BUS_ + 2) /**< BUS interface mode for indirect */
+
+#define _WIZCHIP_IO_MODE_SPI_VDM_ (_WIZCHIP_IO_MODE_SPI_ + 1)  /**< SPI interface mode for variable length data*/
+#define _WIZCHIP_IO_MODE_SPI_FDM_ (_WIZCHIP_IO_MODE_SPI_ + 2)  /**< SPI interface mode for fixed length data mode*/
+#define _WIZCHIP_IO_MODE_SPI_5500_ (_WIZCHIP_IO_MODE_SPI_ + 3) /**< SPI interface mode for fixed length data mode*/
+
+#if (_WIZCHIP_ == W5100)
+#define _WIZCHIP_ID_ "W5100\0"
+    /**
+     * @brief Define interface mode.
+     * @todo you should select interface mode as chip. Select one of @ref \_WIZCHIP_IO_MODE_SPI_ , @ref \_WIZCHIP_IO_MODE_BUS_DIR_ or @ref \_WIZCHIP_IO_MODE_BUS_INDIR_
+     */
+    // 	#define _WIZCHIP_IO_MODE_           _WIZCHIP_IO_MODE_BUS_DIR_
+    //	#define _WIZCHIP_IO_MODE_           _WIZCHIP_IO_MODE_BUS_INDIR_
+#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_
+
+    // A20150601 : Define the unit of IO DATA.
+    typedef uint8_t iodata_t;
+    // A20150401 : Indclude W5100.h file
+#include "W5100/w5100.h"
+
+#elif (_WIZCHIP_ == W5100S)
+#define _WIZCHIP_ID_ "W5100S\0"
+/**
+ * @brief Define interface mode.
+ * @todo you should select interface mode as chip. Select one of @ref \_WIZCHIP_IO_MODE_SPI_ , @ref \_WIZCHIP_IO_MODE_BUS_DIR_ or @ref \_WIZCHIP_IO_MODE_BUS_INDIR_
+ */
+//	#define _WIZCHIP_IO_MODE_           _WIZCHIP_IO_MODE_BUS_INDIR_
+// #define _WIZCHIP_IO_MODE_           _WIZCHIP_IO_MODE_SPI_5500_
+#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_
+
+// A20150601 : Define the unit of IO DATA.
+typedef uint8_t iodata_t;
+// A20150401 : Indclude W5100.h file
+#include "W5100S/w5100s.h"
+#elif (_WIZCHIP_ == W5200)
+#define _WIZCHIP_ID_ "W5200\0"
+/**
+ * @brief Define interface mode.
+ * @todo you should select interface mode as chip. Select one of @ref \_WIZCHIP_IO_MODE_SPI_ or @ref \	_WIZCHIP_IO_MODE_BUS_INDIR_
+ */
+#ifndef _WIZCHIP_IO_MODE_
+// #define _WIZCHIP_IO_MODE_           _WIZCHIP_IO_MODE_BUS_INDIR_
+#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_
+#endif
+// A20150601 : Define the unit of IO DATA.
+typedef uint8_t iodata_t;
+#include "W5200/w5200.h"
+#elif (_WIZCHIP_ == W5500)
+#define _WIZCHIP_ID_ "W5500\0"
+
+/**
+ * @brief Define interface mode. \n
+ * @todo Should select interface mode as chip.
+ *        - @ref \_WIZCHIP_IO_MODE_SPI_ \n
+ *          -@ref \_WIZCHIP_IO_MODE_SPI_VDM_ : Valid only in @ref \_WIZCHIP_ == W5500 \n
+ *          -@ref \_WIZCHIP_IO_MODE_SPI_FDM_ : Valid only in @ref \_WIZCHIP_ == W5500 \n
+ *        - @ref \_WIZCHIP_IO_MODE_BUS_ \n
+ *          - @ref \_WIZCHIP_IO_MODE_BUS_DIR_ \n
+ *          - @ref \_WIZCHIP_IO_MODE_BUS_INDIR_ \n
+ *        - Others will be defined in future. \n\n
+ *        ex> <code> #define \_WIZCHIP_IO_MODE_ \_WIZCHIP_IO_MODE_SPI_VDM_ </code>
+ *
+ */
+#ifndef _WIZCHIP_IO_MODE_
+// #define _WIZCHIP_IO_MODE_           _WIZCHIP_IO_MODE_SPI_FDM_
+#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_VDM_
+#endif
+// A20150601 : Define the unit of IO DATA.
+typedef uint8_t iodata_t;
+#include "W5500/w5500.h"
+#elif (_WIZCHIP_ == W5300)
+#define _WIZCHIP_ID_ "W5300\0"
+/**
+ * @brief Define interface mode.
+ * @todo you should select interface mode as chip. Select one of @ref \_WIZCHIP_IO_MODE_SPI_ , @ref \_WIZCHIP_IO_MODE_BUS_DIR_ or @ref \_WIZCHIP_IO_MODE_BUS_INDIR_
+ */
+#ifndef _WIZCHIP_IO_MODE_
+#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_DIR_
+// #define _WIZCHIP_IO_MODE_           _WIZCHIP_IO_MODE_BUS_INDIR_
+#endif
+
+// A20150601 : Define the unit and bus width of IO DATA.
+/**
+ * @brief Select the data width 8 or 16 bits.
+ * @todo you should select the bus width. Select one of 8 or 16.
+ */
+#ifndef _WIZCHIP_IO_BUS_WIDTH_
+#define _WIZCHIP_IO_BUS_WIDTH_ 16 // 8
+#endif
+#if _WIZCHIP_IO_BUS_WIDTH_ == 8
+typedef uint8_t iodata_t;
+#elif _WIZCHIP_IO_BUS_WIDTH_ == 16
+typedef uint16_t iodata_t;
+#else
+#error "Unknown _WIZCHIP_IO_BUS_WIDTH_. It should be 8 or 16."
+#endif
+//
+#include "W5300/w5300.h"
+#else
+#error "Unknown defined _WIZCHIP_. You should define one of 5100, 5200, and 5500 !!!"
+#endif
+
+#ifndef _WIZCHIP_IO_MODE_
+#error "Undefined _WIZCHIP_IO_MODE_. You should define it !!!"
+#endif
+
+/**
+ * @brief Define I/O base address when BUS IF mode.
+ * @todo Should re-define it to fit your system when BUS IF Mode (@ref \_WIZCHIP_IO_MODE_BUS_,
+ *       @ref \_WIZCHIP_IO_MODE_BUS_DIR_, @ref \_WIZCHIP_IO_MODE_BUS_INDIR_). \n\n
+ *       ex> <code> #define \_WIZCHIP_IO_BASE_      0x00008000 </code>
+ */
+#if _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_BUS_
+    //	#define _WIZCHIP_IO_BASE_				0x60000000	// for 5100S IND
+#define _WIZCHIP_IO_BASE_ 0x68000000 // for W5300
+#elif _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_SPI_
+#define _WIZCHIP_IO_BASE_ 0x00000000 // for 5100S SPI
+#endif
+
+#ifndef _WIZCHIP_IO_BASE_
+#define _WIZCHIP_IO_BASE_ 0x00000000 // 0x8000
+#endif
+
+// M20150401 : Typing Error
+// #if _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_BUS
+#if _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_BUS_
+#ifndef _WIZCHIP_IO_BASE_
+#error "You should be define _WIZCHIP_IO_BASE to fit your system memory map."
+#endif
+#endif
+
+#if _WIZCHIP_ >= W5200
+#define _WIZCHIP_SOCK_NUM_ 8 ///< The count of independant socket of @b WIZCHIP
+#else
+#define _WIZCHIP_SOCK_NUM_ 4 ///< The count of independant socket of @b WIZCHIP
+#endif
+
+    /********************************************************
+     * WIZCHIP BASIC IF functions for SPI, SDIO, I2C , ETC.
+     *********************************************************/
+    /**
+     * @ingroup DATA_TYPE
+     * @brief The set of callback functions for W5500:@ref WIZCHIP_IO_Functions W5200:@ref WIZCHIP_IO_Functions_W5200
+     */
+    typedef struct __WIZCHIP
+    {
+        uint16_t if_mode; ///< host interface mode
+        uint8_t id[8];    ///< @b WIZCHIP ID such as @b 5100, @b 5100S, @b 5200, @b 5500, and so on.
+        /**
+         * The set of critical section callback func.
+         */
+        struct _CRIS
+        {
+            void (*_enter)(void); ///< crtical section enter
+            void (*_exit)(void);  ///< critial section exit
+        } CRIS;
+        /**
+         *  The set of @ref \_WIZCHIP_ select control callback func.
+         */
+        struct _CS
+        {
+            void (*_select)(void);   ///< @ref \_WIZCHIP_ selected
+            void (*_deselect)(void); ///< @ref \_WIZCHIP_ deselected
+        } CS;
+        /**
+         * The set of interface IO callback func.
+         */
+        union _IF
+        {
+            /**
+             * For BUS interface IO
+             */
+            // M20156501 : Modify the function name for integrating with W5300
+            // struct
+            //{
+            //    uint8_t  (*_read_byte)  (uint32_t AddrSel);
+            //    void     (*_write_byte) (uint32_t AddrSel, uint8_t wb);
+            // }BUS;
+            struct
+            {
+                iodata_t (*_read_data)(uint32_t AddrSel);
+                void (*_write_data)(uint32_t AddrSel, iodata_t wb);
+            } BUS;
+
+            /**
+             * For SPI interface IO
+             */
+            struct
+            {
+                uint8_t (*_read_byte)(void);
+                void (*_write_byte)(uint8_t wb);
+                void (*_read_burst)(uint8_t *pBuf, uint16_t len);
+                void (*_write_burst)(uint8_t *pBuf, uint16_t len);
+            } SPI;
+            // To be added
+            //
+        } IF;
+    } _WIZCHIP;
+
+    extern _WIZCHIP WIZCHIP;
+
+    /**
+     * @ingroup DATA_TYPE
+     *  WIZCHIP control type enumration used in @ref ctlwizchip().
+     */
+    typedef enum
+    {
+        CW_RESET_WIZCHIP, ///< Resets WIZCHIP by softly
+        CW_INIT_WIZCHIP,  ///< Initializes to WIZCHIP with SOCKET buffer size 2 or 1 dimension array typed uint8_t.
+        CW_GET_INTERRUPT, ///< Get Interrupt status of WIZCHIP
+        CW_CLR_INTERRUPT, ///< Clears interrupt
+        CW_SET_INTRMASK,  ///< Masks interrupt
+        CW_GET_INTRMASK,  ///< Get interrupt mask
+        CW_SET_INTRTIME,  ///< Set interval time between the current and next interrupt.
+        CW_GET_INTRTIME,  ///< Set interval time between the current and next interrupt.
+        CW_GET_ID,        ///< Gets WIZCHIP name.
+
+        // D20150601 : For no modification your application code
+        // #if _WIZCHIP_ ==  W5500
+        CW_RESET_PHY,      ///< Resets internal PHY. Valid Only W5500
+        CW_SET_PHYCONF,    ///< When PHY configured by internal register, PHY operation mode (Manual/Auto, 10/100, Half/Full). Valid Only W5000
+        CW_GET_PHYCONF,    ///< Get PHY operation mode in internal register. Valid Only W5500
+        CW_GET_PHYSTATUS,  ///< Get real PHY status on operating. Valid Only W5500
+        CW_SET_PHYPOWMODE, ///< Set PHY power mode as normal and down when PHYSTATUS.OPMD == 1. Valid Only W5500
+                           // #endif
+        // D20150601 : For no modification your application code
+        // #if _WIZCHIP_ == W5200 || _WIZCHIP_ == W5500
+        CW_GET_PHYPOWMODE, ///< Get PHY Power mode as down or normal, Valid Only W5100, W5200
+        CW_GET_PHYLINK     ///< Get PHY Link status, Valid Only W5100, W5200
+        // #endif
+    } ctlwizchip_type;
+
+    /**
+     * @ingroup DATA_TYPE
+     *  Network control type enumration used in @ref ctlnetwork().
+     */
+    typedef enum
+    {
+        CN_SET_NETINFO, ///< Set Network with @ref wiz_NetInfo
+        CN_GET_NETINFO, ///< Get Network with @ref wiz_NetInfo
+        CN_SET_NETMODE, ///< Set network mode as WOL, PPPoE, Ping Block, and Force ARP mode
+        CN_GET_NETMODE, ///< Get network mode as WOL, PPPoE, Ping Block, and Force ARP mode
+        CN_SET_TIMEOUT, ///< Set network timeout as retry count and time.
+        CN_GET_TIMEOUT, ///< Get network timeout as retry count and time.
+    } ctlnetwork_type;
+
+    /**
+     * @ingroup DATA_TYPE
+     *  Interrupt kind when CW_SET_INTRRUPT, CW_GET_INTERRUPT, CW_SET_INTRMASK
+     *  and CW_GET_INTRMASK is used in @ref ctlnetwork().
+     *  It can be used with OR operation.
+     */
+    typedef enum
+    {
+#if _WIZCHIP_ == W5500
+        IK_WOL = (1 << 4), ///< Wake On Lan by receiving the magic packet. Valid in W500.
+#elif _WIZCHIP_ == W5300
+    IK_FMTU = (1 << 4),       ///< Received a ICMP message (Fragment MTU)
+#endif
+
+        IK_PPPOE_TERMINATED = (1 << 5), ///< PPPoE Disconnected
+
+#if _WIZCHIP_ != W5200
+        IK_DEST_UNREACH = (1 << 6), ///< Destination IP & Port Unreachable, No use in W5200
+#endif
+
+        IK_IP_CONFLICT = (1 << 7), ///< IP conflict occurred
+
+        IK_SOCK_0 = (1 << 8),  ///< Socket 0 interrupt
+        IK_SOCK_1 = (1 << 9),  ///< Socket 1 interrupt
+        IK_SOCK_2 = (1 << 10), ///< Socket 2 interrupt
+        IK_SOCK_3 = (1 << 11), ///< Socket 3 interrupt
+#if _WIZCHIP_ > W5100S
+        IK_SOCK_4 = (1 << 12), ///< Socket 4 interrupt, No use in 5100
+        IK_SOCK_5 = (1 << 13), ///< Socket 5 interrupt, No use in 5100
+        IK_SOCK_6 = (1 << 14), ///< Socket 6 interrupt, No use in 5100
+        IK_SOCK_7 = (1 << 15), ///< Socket 7 interrupt, No use in 5100
+#endif
+
+#if _WIZCHIP_ > W5100S
+        IK_SOCK_ALL = (0xFF << 8) ///< All Socket interrupt
+#else
+    IK_SOCK_ALL = (0x0F << 8) ///< All Socket interrupt
+#endif
+    } intr_kind;
+
+#define PHY_CONFBY_HW 0     ///< Configured PHY operation mode by HW pin
+#define PHY_CONFBY_SW 1     ///< Configured PHY operation mode by SW register
+#define PHY_MODE_MANUAL 0   ///< Configured PHY operation mode with user setting.
+#define PHY_MODE_AUTONEGO 1 ///< Configured PHY operation mode with auto-negotiation
+#define PHY_SPEED_10 0      ///< Link Speed 10
+#define PHY_SPEED_100 1     ///< Link Speed 100
+#define PHY_DUPLEX_HALF 0   ///< Link Half-Duplex
+#define PHY_DUPLEX_FULL 1   ///< Link Full-Duplex
+#define PHY_LINK_OFF 0      ///< Link Off
+#define PHY_LINK_ON 1       ///< Link On
+#define PHY_POWER_NORM 0    ///< PHY power normal mode
+#define PHY_POWER_DOWN 1    ///< PHY power down mode
+
+#if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5500
+    /**
+     * @ingroup DATA_TYPE
+     *  It configures PHY configuration when CW_SET PHYCONF or CW_GET_PHYCONF in W5500,
+     *  and it indicates the real PHY status configured by HW or SW in all WIZCHIP. \n
+     *  Valid only in W5500.
+     */
+    typedef struct wiz_PhyConf_t
+    {
+        uint8_t by;     ///< set by @ref PHY_CONFBY_HW or @ref PHY_CONFBY_SW
+        uint8_t mode;   ///< set by @ref PHY_MODE_MANUAL or @ref PHY_MODE_AUTONEGO
+        uint8_t speed;  ///< set by @ref PHY_SPEED_10 or @ref PHY_SPEED_100
+        uint8_t duplex; ///< set by @ref PHY_DUPLEX_HALF @ref PHY_DUPLEX_FULL
+                        // uint8_t power;  ///< set by @ref PHY_POWER_NORM or @ref PHY_POWER_DOWN
+        // uint8_t link;   ///< Valid only in CW_GET_PHYSTATUS. set by @ref PHY_LINK_ON or PHY_DUPLEX_OFF
+    } wiz_PhyConf;
+#endif
+
+    /**
+     * @ingroup DATA_TYPE
+     *  It used in setting dhcp_mode of @ref wiz_NetInfo.
+     */
+    typedef enum
+    {
+        NETINFO_STATIC = 1, ///< Static IP configuration by manually.
+        NETINFO_DHCP        ///< Dynamic IP configruation from a DHCP sever
+    } dhcp_mode;
+
+    /**
+     * @ingroup DATA_TYPE
+     *  Network Information for WIZCHIP
+     */
+    typedef struct wiz_NetInfo_t
+    {
+        uint8_t mac[6]; ///< Source Mac Address
+        uint8_t ip[4];  ///< Source IP Address
+        uint8_t sn[4];  ///< Subnet Mask
+        uint8_t gw[4];  ///< Gateway IP Address
+        uint8_t dns[4]; ///< DNS server IP Address
+        dhcp_mode dhcp; ///< 1 - Static, 2 - DHCP
+    } wiz_NetInfo;
+
+    /**
+     * @ingroup DATA_TYPE
+     *  Network mode
+     */
+    typedef enum
+    {
+#if _WIZCHIP_ == W5500
+        NM_FORCEARP = (1 << 1), ///< Force to APP send whenever udp data is sent. Valid only in W5500
+#endif
+        NM_WAKEONLAN = (1 << 5), ///< Wake On Lan
+        NM_PINGBLOCK = (1 << 4), ///< Block ping-request
+        NM_PPPOE = (1 << 3),     ///< PPPoE mode
+    } netmode_type;
+
+    /**
+     * @ingroup DATA_TYPE
+     *  Used in CN_SET_TIMEOUT or CN_GET_TIMEOUT of @ref ctlwizchip() for timeout configruation.
+     */
+    typedef struct wiz_NetTimeout_t
+    {
+        uint8_t retry_cnt;   ///< retry count
+        uint16_t time_100us; ///< time unit 100us
+    } wiz_NetTimeout;
+
+    /**
+     *@brief Registers call back function for critical section of I/O functions such as
+     *\ref WIZCHIP_READ, @ref WIZCHIP_WRITE, @ref WIZCHIP_READ_BUF and @ref WIZCHIP_WRITE_BUF.
+     *@param cris_en : callback function for critical section enter.
+     *@param cris_ex : callback function for critical section exit.
+     *@todo Describe @ref WIZCHIP_CRITICAL_ENTER and @ref WIZCHIP_CRITICAL_EXIT marco or register your functions.
+     *@note If you do not describe or register, default functions(@ref wizchip_cris_enter & @ref wizchip_cris_exit) is called.
+     */
+    void reg_wizchip_cris_cbfunc(void (*cris_en)(void), void (*cris_ex)(void));
+
+    /**
+     *@brief Registers call back function for WIZCHIP select & deselect.
+     *@param cs_sel : callback function for WIZCHIP select
+     *@param cs_desel : callback fucntion for WIZCHIP deselect
+     *@todo Describe @ref wizchip_cs_select and @ref wizchip_cs_deselect function or register your functions.
+     *@note If you do not describe or register, null function is called.
+     */
+    void reg_wizchip_cs_cbfunc(void (*cs_sel)(void), void (*cs_desel)(void));
+
+    /**
+     *@brief Registers call back function for bus interface.
+     *@param bus_rb   : callback function to read byte data using system bus
+     *@param bus_wb   : callback function to write byte data using system bus
+     *@todo Describe @ref wizchip_bus_readbyte and @ref wizchip_bus_writebyte function
+     *or register your functions.
+     *@note If you do not describe or register, null function is called.
+     */
+    // M20150601 : For integrating with W5300
+    // void reg_wizchip_bus_cbfunc(uint8_t (*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, uint8_t wb));
+    void reg_wizchip_bus_cbfunc(iodata_t (*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, iodata_t wb));
+
+    /**
+     *@brief Registers call back function for SPI interface.
+     *@param spi_rb : callback function to read byte using SPI
+     *@param spi_wb : callback function to write byte using SPI
+     *@todo Describe \ref wizchip_spi_readbyte and \ref wizchip_spi_writebyte function
+     *or register your functions.
+     *@note If you do not describe or register, null function is called.
+     */
+    void reg_wizchip_spi_cbfunc(uint8_t (*spi_rb)(void), void (*spi_wb)(uint8_t wb));
+
+    /**
+     *@brief Registers call back function for SPI interface.
+     *@param spi_rb : callback function to burst read using SPI
+     *@param spi_wb : callback function to burst write using SPI
+     *@todo Describe \ref wizchip_spi_readbyte and \ref wizchip_spi_writebyte function
+     *or register your functions.
+     *@note If you do not describe or register, null function is called.
+     */
+    void reg_wizchip_spiburst_cbfunc(void (*spi_rb)(uint8_t *pBuf, uint16_t len), void (*spi_wb)(uint8_t *pBuf, uint16_t len));
+
+    /**
+     * @ingroup extra_functions
+     * @brief Controls to the WIZCHIP.
+     * @details Resets WIZCHIP & internal PHY, Configures PHY mode, Monitor PHY(Link,Speed,Half/Full/Auto),
+     * controls interrupt & mask and so on.
+     * @param cwtype : Decides to the control type
+     * @param arg : arg type is dependent on cwtype.
+     * @return  0 : Success \n
+     *         -1 : Fail because of invalid \ref ctlwizchip_type or unsupported \ref ctlwizchip_type in WIZCHIP
+     */
+    int8_t ctlwizchip(ctlwizchip_type cwtype, void *arg);
+
+    /**
+     * @ingroup extra_functions
+     * @brief Controls to network.
+     * @details Controls to network environment, mode, timeout and so on.
+     * @param cntype : Input. Decides to the control type
+     * @param arg : Inout. arg type is dependent on cntype.
+     * @return -1 : Fail because of invalid \ref ctlnetwork_type or unsupported \ref ctlnetwork_type in WIZCHIP \n
+     *          0 : Success
+     */
+    int8_t ctlnetwork(ctlnetwork_type cntype, void *arg);
+
+    /*
+     * The following functions are implemented for internal use.
+     * but You can call these functions for code size reduction instead of ctlwizchip() and ctlnetwork().
+     */
+
+    /**
+     * @ingroup extra_functions
+     * @brief Reset WIZCHIP by softly.
+     */
+    void wizchip_sw_reset(void);
+
+    /**
+     * @ingroup extra_functions
+     * @brief Initializes WIZCHIP with socket buffer size
+     * @param txsize Socket tx buffer sizes. If null, initialized the default size 2KB.
+     * @param rxsize Socket rx buffer sizes. If null, initialized the default size 2KB.
+     * @return 0 : succcess \n
+     *        -1 : fail. Invalid buffer size
+     */
+    int8_t wizchip_init(uint8_t *txsize, uint8_t *rxsize);
+
+    /**
+     * @ingroup extra_functions
+     * @brief Clear Interrupt of WIZCHIP.
+     * @param intr : @ref intr_kind value operated OR. It can type-cast to uint16_t.
+     */
+    void wizchip_clrinterrupt(intr_kind intr);
+
+    /**
+     * @ingroup extra_functions
+     * @brief Get Interrupt of WIZCHIP.
+     * @return @ref intr_kind value operated OR. It can type-cast to uint16_t.
+     */
+    intr_kind wizchip_getinterrupt(void);
+
+    /**
+     * @ingroup extra_functions
+     * @brief Mask or Unmask Interrupt of WIZCHIP.
+     * @param intr : @ref intr_kind value operated OR. It can type-cast to uint16_t.
+     */
+    void wizchip_setinterruptmask(intr_kind intr);
+
+    /**
+     * @ingroup extra_functions
+     * @brief Get Interrupt mask of WIZCHIP.
+     * @return : The operated OR vaule of @ref intr_kind. It can type-cast to uint16_t.
+     */
+    intr_kind wizchip_getinterruptmask(void);
+
+// todo
+#if _WIZCHIP_ > W5100
+    int8_t wizphy_getphylink(void);  ///< get the link status of phy in WIZCHIP. No use in W5100
+    int8_t wizphy_getphypmode(void); ///< get the power mode of PHY in WIZCHIP. No use in W5100
+#endif
+
+#if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5500
+    void wizphy_reset(void); ///< Reset phy. Vailid only in W5500
+                             /**
+                              * @ingroup extra_functions
+                              * @brief Set the phy information for WIZCHIP without power mode
+                              * @param phyconf : @ref wiz_PhyConf
+                              */
+    void wizphy_setphyconf(wiz_PhyConf *phyconf);
+    /**
+     * @ingroup extra_functions
+     * @brief Get phy configuration information.
+     * @param phyconf : @ref wiz_PhyConf
+     */
+    void wizphy_getphyconf(wiz_PhyConf *phyconf);
+    /**
+     * @ingroup extra_functions
+     * @brief Get phy status.
+     * @param phyconf : @ref wiz_PhyConf
+     */
+    void wizphy_getphystat(wiz_PhyConf *phyconf);
+    /**
+     * @ingroup extra_functions
+     * @brief set the power mode of phy inside WIZCHIP. Refer to @ref PHYCFGR in W5500, @ref PHYSTATUS in W5200
+     * @param pmode Settig value of power down mode.
+     */
+    int8_t wizphy_setphypmode(uint8_t pmode);
+#endif
+
+    /**
+     * @ingroup extra_functions
+     * @brief Set the network information for WIZCHIP
+     * @param pnetinfo : @ref wizNetInfo
+     */
+    void wizchip_setnetinfo(wiz_NetInfo *pnetinfo);
+
+    /**
+     * @ingroup extra_functions
+     * @brief Get the network information for WIZCHIP
+     * @param pnetinfo : @ref wizNetInfo
+     */
+    void wizchip_getnetinfo(wiz_NetInfo *pnetinfo);
+
+    /**
+     * @ingroup extra_functions
+     * @brief Set the network mode such WOL, PPPoE, Ping Block, and etc.
+     * @param pnetinfo Value of network mode. Refer to @ref netmode_type.
+     */
+    int8_t wizchip_setnetmode(netmode_type netmode);
+
+    /**
+     * @ingroup extra_functions
+     * @brief Get the network mode such WOL, PPPoE, Ping Block, and etc.
+     * @return Value of network mode. Refer to @ref netmode_type.
+     */
+    netmode_type wizchip_getnetmode(void);
+
+    /**
+     * @ingroup extra_functions
+     * @brief Set retry time value(@ref _RTR_) and retry count(@ref _RCR_).
+     * @details @ref _RTR_ configures the retransmission timeout period and @ref _RCR_ configures the number of time of retransmission.
+     * @param nettime @ref _RTR_ value and @ref _RCR_ value. Refer to @ref wiz_NetTimeout.
+     */
+    void wizchip_settimeout(wiz_NetTimeout *nettime);
+
+    /**
+     * @ingroup extra_functions
+     * @brief Get retry time value(@ref _RTR_) and retry count(@ref _RCR_).
+     * @details @ref _RTR_ configures the retransmission timeout period and @ref _RCR_ configures the number of time of retransmission.
+     * @param nettime @ref _RTR_ value and @ref _RCR_ value. Refer to @ref wiz_NetTimeout.
+     */
+    void wizchip_gettimeout(wiz_NetTimeout *nettime);
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _WIZCHIP_CONF_H_

+ 1019 - 0
ioLibrary/wizchip/wizchip_socket.c

@@ -0,0 +1,1019 @@
+//*****************************************************************************
+//
+//! \file wizchip_socket.c
+//! \brief SOCKET APIs Implements file.
+//! \details SOCKET APIs like as Berkeley Socket APIs.
+//! \version 1.0.3
+//! \date 2013/10/21
+//! \par  Revision history
+//!       <2015/02/05> Notice
+//!        The version history is not updated after this point.
+//!        Download the latest version directly from GitHub. Please visit the our GitHub repository for ioLibrary.
+//!        >> https://github.com/Wiznet/ioLibrary_Driver
+//!       <2014/05/01> V1.0.3. Refer to M20140501
+//!         1. Implicit type casting -> Explicit type casting.
+//!         2. replace 0x01 with PACK_REMAINED in recvfrom()
+//!         3. Validation a destination ip in connect() & sendto():
+//!            It occurs a fatal error on converting unint32 address if uint8* addr parameter is not aligned by 4byte address.
+//!            Copy 4 byte addr value into temporary uint32 variable and then compares it.
+//!       <2013/12/20> V1.0.2 Refer to M20131220
+//!                    Remove Warning.
+//!       <2013/11/04> V1.0.1 2nd Release. Refer to "20131104".
+//!                    In sendto(), Add to clear timeout interrupt status (Sn_IR_TIMEOUT)
+//!       <2013/10/21> 1st Release
+//! \author MidnightCow
+//! \copyright
+//!
+//! Copyright (c)  2013, WIZnet Co., LTD.
+//! All rights reserved.
+//!
+//! Redistribution and use in source and binary forms, with or without
+//! modification, are permitted provided that the following conditions
+//! are met:
+//!
+//!     * Redistributions of source code must retain the above copyright
+//! notice, this list of conditions and the following disclaimer.
+//!     * Redistributions in binary form must reproduce the above copyright
+//! notice, this list of conditions and the following disclaimer in the
+//! documentation and/or other materials provided with the distribution.
+//!     * Neither the name of the <ORGANIZATION> nor the names of its
+//! contributors may be used to endorse or promote products derived
+//! from this software without specific prior written permission.
+//!
+//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+//! THE POSSIBILITY OF SUCH DAMAGE.
+//
+//*****************************************************************************
+#include "wizchip_socket.h"
+#include "RyanW5500Store.h"
+
+#define RyanWizchipCheck(EX, count, code) RyanWizchipCheckCode(EX, count, 1, code, { NULL; })
+
+#define RyanWizchipCheckCode(EX, count, ms, code, userCode) \
+    for (uint16_t i = 0; (EX); i++)                         \
+    {                                                       \
+        {                                                   \
+            userCode                                        \
+        }                                                   \
+        if (i >= count)                                     \
+        {                                                   \
+            return (code);                                  \
+        }                                                   \
+        delay(ms);                                          \
+    }
+
+// M20150401 : Typing Error
+// #define SOCK_ANY_PORT_NUM  0xC000;
+#define SOCK_ANY_PORT_NUM 0xC000
+
+static uint16_t sock_any_port = SOCK_ANY_PORT_NUM;
+static uint16_t sock_io_mode = 0;
+static uint16_t sock_is_sending = 0;
+
+static uint16_t sock_remained_size[_WIZCHIP_SOCK_NUM_] = {0};
+
+// M20150601 : For extern decleation
+// static uint8_t  sock_pack_info[_WIZCHIP_SOCK_NUM_] = {0,};
+uint8_t sock_pack_info[_WIZCHIP_SOCK_NUM_] = {0};
+//
+
+#if _WIZCHIP_ == 5200
+static uint16_t sock_next_rd[_WIZCHIP_SOCK_NUM_] = {y0};
+#endif
+
+// A20150601 : For integrating with W5300
+#if _WIZCHIP_ == 5300
+uint8_t sock_remained_byte[_WIZCHIP_SOCK_NUM_] = {0}; // set by wiz_recv_data()
+#endif
+
+#define CHECK_SOCKNUM()              \
+    do                               \
+    {                                \
+        if (sn > _WIZCHIP_SOCK_NUM_) \
+            return SOCKERR_SOCKNUM;  \
+    } while (0);
+
+#define CHECK_SOCKMODE(mode)               \
+    do                                     \
+    {                                      \
+        if ((getSn_MR(sn) & 0x0F) != mode) \
+            return SOCKERR_SOCKMODE;       \
+    } while (0);
+
+#define CHECK_SOCKINIT()                 \
+    do                                   \
+    {                                    \
+        if ((getSn_SR(sn) != SOCK_INIT)) \
+            return SOCKERR_SOCKINIT;     \
+    } while (0);
+
+#define CHECK_SOCKDATA()            \
+    do                              \
+    {                               \
+        if (len == 0)               \
+            return SOCKERR_DATALEN; \
+    } while (0);
+
+int8_t wizchip_socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag)
+{
+
+    CHECK_SOCKNUM();
+    switch (protocol)
+    {
+    case Sn_MR_TCP:
+    {
+        uint32_t taddr;
+        getSIPR((uint8_t *)&taddr); // 源iP寄存器
+        if (taddr == 0)
+            return SOCKERR_SOCKINIT;
+        break;
+    }
+
+    case Sn_MR_UDP:
+    case Sn_MR_MACRAW:
+    case Sn_MR_IPRAW:
+        break;
+#if (_WIZCHIP_ < 5200)
+    case Sn_MR_PPPoE:
+        break;
+#endif
+    default:
+        return SOCKERR_SOCKMODE;
+    }
+    // M20150601 : For SF_TCP_ALIGN & W5300
+    // if((flag & 0x06) != 0) return SOCKERR_SOCKFLAG;
+    if ((flag & 0x04) != 0)
+        return SOCKERR_SOCKFLAG;
+#if _WIZCHIP_ == 5200
+    if (flag & 0x10)
+        return SOCKERR_SOCKFLAG;
+#endif
+
+    if (flag != 0)
+    {
+        switch (protocol)
+        {
+        case Sn_MR_TCP:
+// M20150601 :  For SF_TCP_ALIGN & W5300
+#if _WIZCHIP_ == 5300
+            if ((flag & (SF_TCP_NODELAY | SF_IO_NONBLOCK | SF_TCP_ALIGN)) == 0)
+                return SOCKERR_SOCKFLAG;
+#else
+            if ((flag & (SF_TCP_NODELAY | SF_IO_NONBLOCK)) == 0)
+                return SOCKERR_SOCKFLAG;
+#endif
+
+            break;
+        case Sn_MR_UDP:
+            if (flag & SF_IGMP_VER2)
+            {
+                if ((flag & SF_MULTI_ENABLE) == 0)
+                    return SOCKERR_SOCKFLAG;
+            }
+#if _WIZCHIP_ == 5500
+            if (flag & SF_UNI_BLOCK)
+            {
+                if ((flag & SF_MULTI_ENABLE) == 0)
+                    return SOCKERR_SOCKFLAG;
+            }
+#endif
+            break;
+        default:
+            break;
+        }
+    }
+    wizchip_close(sn);
+// M20150601
+#if _WIZCHIP_ == 5300
+    setSn_MR(sn, ((uint16_t)(protocol | (flag & 0xF0))) | (((uint16_t)(flag & 0x02)) << 7));
+#else
+    setSn_MR(sn, (protocol | (flag & 0xF0)));
+#endif
+    if (!port)
+    {
+        port = sock_any_port++;
+        if (sock_any_port == 0xFFF0)
+            sock_any_port = SOCK_ANY_PORT_NUM;
+    }
+    setSn_PORT(sn, port);
+    setSn_CR(sn, Sn_CR_OPEN);
+
+    RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+
+    // A20150401 : For release the previous sock_io_mode
+    sock_io_mode &= ~(1 << sn);
+    //
+    sock_io_mode |= ((flag & SF_IO_NONBLOCK) << sn);
+    sock_is_sending &= ~(1 << sn);
+    sock_remained_size[sn] = 0;
+    // M20150601 : repalce 0 with PACK_COMPLETED
+    // sock_pack_info[sn] = 0;
+    sock_pack_info[sn] = PACK_COMPLETED;
+    //
+    RyanWizchipCheck(getSn_SR(sn) == SOCK_CLOSED, 10, SOCKERR_SOCKCLOSED);
+
+    return (int8_t)sn;
+}
+
+int8_t wizchip_close(uint8_t sn)
+{
+    CHECK_SOCKNUM();
+// A20160426 : Applied the erratum 1 of W5300
+#if (_WIZCHIP_ == 5300)
+    // M20160503 : Wrong socket parameter. s -> sn
+    // if( ((getSn_MR(s)& 0x0F) == Sn_MR_TCP) && (getSn_TX_FSR(s) != getSn_TxMAX(s)) )
+    if (((getSn_MR(sn) & 0x0F) == Sn_MR_TCP) && (getSn_TX_FSR(sn) != getSn_TxMAX(sn)))
+    {
+        uint8_t destip[4] = {0, 0, 0, 1};
+        // TODO
+        // You can wait for completing to sending data;
+        // wait about 1 second;
+        // if you have completed to send data, skip the code of erratum 1
+        // ex> wait_1s();
+        //     if (getSn_TX_FSR(s) == getSn_TxMAX(s)) continue;
+        //
+        // M20160503 : The socket() of close() calls close() itself again. It occures a infinite loop - close()->socket()->close()->socket()-> ~
+        // socket(s,Sn_MR_UDP,0x3000,0);
+        // sendto(s,destip,1,destip,0x3000); // send the dummy data to an unknown destination(0.0.0.1).
+        setSn_MR(sn, Sn_MR_UDP);
+        setSn_PORTR(sn, 0x3000);
+        setSn_CR(sn, Sn_CR_OPEN);
+        RyanWizchipCheck(getSn_CR(sn) != 0, 10, SOCKERR_SOCKCLOSED);
+
+        RyanWizchipCheck(getSn_SR(sn) != SOCK_UDP, 10, SOCKERR_SOCKCLOSED);
+
+        sendto(sn, destip, 1, destip, 0x3000); // send the dummy data to an unknown destination(0.0.0.1).
+    };
+#endif
+    setSn_CR(sn, Sn_CR_CLOSE);
+    /* wait to process the command... */
+    RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+    /* clear all interrupt of the socket. */
+    setSn_IR(sn, 0xFF);
+    // A20150401 : Release the sock_io_mode of socket n.
+    sock_io_mode &= ~(1 << sn);
+    //
+    sock_is_sending &= ~(1 << sn);
+    sock_remained_size[sn] = 0;
+    sock_pack_info[sn] = 0;
+    RyanWizchipCheck(getSn_SR(sn) != SOCK_CLOSED, 10, SOCKERR_SOCKCLOSED);
+
+    return SOCK_OK;
+}
+
+int8_t wizchip_listen(uint8_t sn)
+{
+    CHECK_SOCKNUM();
+    CHECK_SOCKMODE(Sn_MR_TCP);
+    CHECK_SOCKINIT();
+    setSn_CR(sn, Sn_CR_LISTEN);
+    RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+
+    for (uint8_t i = 0; getSn_SR(sn) != SOCK_LISTEN; i++)
+    {
+        if (i >= 10)
+        {
+            wizchip_close(sn);
+            return SOCKERR_SOCKCLOSED;
+        }
+
+        delay(2);
+    }
+
+    return SOCK_OK;
+}
+
+int8_t wizchip_connect(uint8_t sn, uint8_t *addr, uint16_t port)
+{
+    CHECK_SOCKNUM();
+    CHECK_SOCKMODE(Sn_MR_TCP);
+    CHECK_SOCKINIT();
+    // M20140501 : For avoiding fatal error on memory align mismatched
+    // if( *((uint32_t*)addr) == 0xFFFFFFFF || *((uint32_t*)addr) == 0) return SOCKERR_IPINVALID;
+    {
+        uint32_t taddr;
+        taddr = ((uint32_t)addr[0] & 0x000000FF);
+        taddr = (taddr << 8) + ((uint32_t)addr[1] & 0x000000FF);
+        taddr = (taddr << 8) + ((uint32_t)addr[2] & 0x000000FF);
+        taddr = (taddr << 8) + ((uint32_t)addr[3] & 0x000000FF);
+        if (taddr == 0xFFFFFFFF || taddr == 0)
+            return SOCKERR_IPINVALID;
+    }
+    //
+
+    if (port == 0)
+        return SOCKERR_PORTZERO;
+    setSn_DIPR(sn, addr);
+    setSn_DPORT(sn, port);
+    setSn_CR(sn, Sn_CR_CONNECT);
+    RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+    if (sock_io_mode & (1 << sn))
+        return SOCK_BUSY;
+
+    RyanWizchipCheckCode(getSn_SR(sn) != SOCK_ESTABLISHED, 1000, 2, SOCKERR_SOCKCLOSED, {
+        if (getSn_IR(sn) & Sn_IR_TIMEOUT)
+        {
+            setSn_IR(sn, Sn_IR_TIMEOUT);
+            return SOCKERR_TIMEOUT;
+        }
+
+        if (getSn_SR(sn) == SOCK_CLOSED)
+        {
+            return SOCKERR_SOCKCLOSED;
+        }
+    });
+
+    return SOCK_OK;
+}
+
+int8_t wizchip_disconnect(uint8_t sn)
+{
+    CHECK_SOCKNUM();
+    CHECK_SOCKMODE(Sn_MR_TCP);
+    setSn_CR(sn, Sn_CR_DISCON);
+    /* wait to process the command... */
+    RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+
+    sock_is_sending &= ~(1 << sn);
+    if (sock_io_mode & (1 << sn))
+        return SOCK_BUSY;
+
+    RyanWizchipCheckCode(getSn_SR(sn) != SOCK_CLOSED, 1000, 2, SOCKERR_SOCKCLOSED, {
+        if (getSn_IR(sn) & Sn_IR_TIMEOUT)
+        {
+            wizchip_close(sn);
+            return SOCKERR_TIMEOUT;
+        }
+    });
+
+    return SOCK_OK;
+}
+
+int32_t wizchip_send(uint8_t sn, uint8_t *buf, uint16_t len)
+{
+    uint8_t tmp = 0;
+    uint16_t freesize = 0;
+
+    CHECK_SOCKNUM();
+    CHECK_SOCKMODE(Sn_MR_TCP);
+    CHECK_SOCKDATA();
+    tmp = getSn_SR(sn);
+    if (tmp != SOCK_ESTABLISHED && tmp != SOCK_CLOSE_WAIT)
+        return SOCKERR_SOCKSTATUS;
+    if (sock_is_sending & (1 << sn))
+    {
+        tmp = getSn_IR(sn);
+        if (tmp & Sn_IR_SENDOK)
+        {
+            setSn_IR(sn, Sn_IR_SENDOK);
+// M20150401 : Typing Error
+// #if _WZICHIP_ == 5200
+#if _WIZCHIP_ == 5200
+            if (getSn_TX_RD(sn) != sock_next_rd[sn])
+            {
+                setSn_CR(sn, Sn_CR_SEND);
+                RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+
+                return SOCK_BUSY;
+            }
+#endif
+            sock_is_sending &= ~(1 << sn);
+        }
+        else if (tmp & Sn_IR_TIMEOUT)
+        {
+            wizchip_close(sn);
+            return SOCKERR_TIMEOUT;
+        }
+        else
+            return SOCK_BUSY;
+    }
+    freesize = getSn_TxMAX(sn);
+    if (len > freesize)
+        len = freesize; // check size not to exceed MAX size.
+
+    RyanWizchipCheckCode(getSn_SR(sn) != SOCK_CLOSED, 1000, 2, SOCKERR_SOCKCLOSED, {
+        freesize = getSn_TX_FSR(sn);
+        tmp = getSn_SR(sn);
+        if ((tmp != SOCK_ESTABLISHED) && (tmp != SOCK_CLOSE_WAIT))
+        {
+            wizchip_close(sn);
+            return SOCKERR_SOCKSTATUS;
+        }
+
+        if ((sock_io_mode & (1 << sn)) && (len > freesize))
+            return SOCK_BUSY;
+
+        if (len <= freesize)
+            break;
+    });
+
+    wiz_send_data(sn, buf, len);
+#if _WIZCHIP_ == 5200
+    sock_next_rd[sn] = getSn_TX_RD(sn) + len;
+#endif
+
+#if _WIZCHIP_ == 5300
+    setSn_TX_WRSR(sn, len);
+#endif
+
+    setSn_CR(sn, Sn_CR_SEND);
+    /* wait to process the command... */
+    RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+    sock_is_sending |= (1 << sn);
+    // M20150409 : Explicit Type Casting
+    // return len;
+    return (int32_t)len;
+}
+
+int32_t wizchip_recv(uint8_t sn, uint8_t *buf, uint16_t len)
+{
+    uint8_t tmp = 0;
+    uint16_t recvsize = 0;
+// A20150601 : For integarating with W5300
+#if _WIZCHIP_ == 5300
+    uint8_t head[2];
+    uint16_t mr;
+#endif
+    //
+    CHECK_SOCKNUM();
+    CHECK_SOCKMODE(Sn_MR_TCP);
+    CHECK_SOCKDATA();
+
+    recvsize = getSn_RxMAX(sn);
+    if (recvsize < len)
+        len = recvsize;
+
+// A20150601 : For Integrating with W5300
+#if _WIZCHIP_ == 5300
+    // sock_pack_info[sn] = PACK_COMPLETED;    // for clear
+    if (sock_remained_size[sn] == 0)
+    {
+#endif
+        //
+        RyanWizchipCheckCode(getSn_SR(sn) != SOCK_CLOSED, 1000, 2, SOCKERR_SOCKCLOSED, {
+            recvsize = getSn_RX_RSR(sn);
+            tmp = getSn_SR(sn);
+            if (tmp != SOCK_ESTABLISHED)
+            {
+                if (tmp == SOCK_CLOSE_WAIT)
+                {
+                    if (recvsize != 0)
+                        break;
+                    else if (getSn_TX_FSR(sn) == getSn_TxMAX(sn))
+                    {
+                        wizchip_close(sn);
+                        return SOCKERR_SOCKSTATUS;
+                    }
+                }
+                else
+                {
+                    wizchip_close(sn);
+                    return SOCKERR_SOCKSTATUS;
+                }
+            }
+            if ((sock_io_mode & (1 << sn)) && (recvsize == 0))
+                return SOCK_BUSY;
+            if (recvsize != 0)
+                break;
+        });
+
+#if _WIZCHIP_ == 5300
+    }
+#endif
+
+// A20150601 : For integrating with W5300
+#if _WIZCHIP_ == 5300
+    if ((sock_remained_size[sn] == 0) || (getSn_MR(sn) & Sn_MR_ALIGN))
+    {
+        mr = getMR();
+        if ((getSn_MR(sn) & Sn_MR_ALIGN) == 0)
+        {
+            wiz_recv_data(sn, head, 2);
+            if (mr & MR_FS)
+                recvsize = (((uint16_t)head[1]) << 8) | ((uint16_t)head[0]);
+            else
+                recvsize = (((uint16_t)head[0]) << 8) | ((uint16_t)head[1]);
+            sock_pack_info[sn] = PACK_FIRST;
+        }
+        sock_remained_size[sn] = recvsize;
+    }
+    if (len > sock_remained_size[sn])
+        len = sock_remained_size[sn];
+    recvsize = len;
+    if (sock_pack_info[sn] & PACK_FIFOBYTE)
+    {
+        *buf = sock_remained_byte[sn];
+        buf++;
+        sock_pack_info[sn] &= ~(PACK_FIFOBYTE);
+        recvsize -= 1;
+        sock_remained_size[sn] -= 1;
+    }
+    if (recvsize != 0)
+    {
+        wiz_recv_data(sn, buf, recvsize);
+        setSn_CR(sn, Sn_CR_RECV);
+        RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+    }
+    sock_remained_size[sn] -= recvsize;
+    if (sock_remained_size[sn] != 0)
+    {
+        sock_pack_info[sn] |= PACK_REMAINED;
+        if (recvsize & 0x1)
+            sock_pack_info[sn] |= PACK_FIFOBYTE;
+    }
+    else
+        sock_pack_info[sn] = PACK_COMPLETED;
+    if (getSn_MR(sn) & Sn_MR_ALIGN)
+        sock_remained_size[sn] = 0;
+        // len = recvsize;
+#else
+    if (recvsize < len)
+        len = recvsize;
+    wiz_recv_data(sn, buf, len);
+    setSn_CR(sn, Sn_CR_RECV);
+    RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+#endif
+
+    // M20150409 : Explicit Type Casting
+    // return len;
+    return (int32_t)len;
+}
+
+int32_t wizchip_sendto(uint8_t sn, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t port)
+{
+    uint8_t tmp = 0;
+    uint16_t freesize = 0;
+    uint32_t taddr;
+
+    CHECK_SOCKNUM();
+    switch (getSn_MR(sn) & 0x0F)
+    {
+    case Sn_MR_UDP:
+    case Sn_MR_MACRAW:
+        //         break;
+        //   #if ( _WIZCHIP_ < 5200 )
+    case Sn_MR_IPRAW:
+        break;
+        //   #endif
+    default:
+        return SOCKERR_SOCKMODE;
+    }
+    CHECK_SOCKDATA();
+    // M20140501 : For avoiding fatal error on memory align mismatched
+    // if(*((uint32_t*)addr) == 0) return SOCKERR_IPINVALID;
+    //{
+    // uint32_t taddr;
+    taddr = ((uint32_t)addr[0]) & 0x000000FF;
+    taddr = (taddr << 8) + ((uint32_t)addr[1] & 0x000000FF);
+    taddr = (taddr << 8) + ((uint32_t)addr[2] & 0x000000FF);
+    taddr = (taddr << 8) + ((uint32_t)addr[3] & 0x000000FF);
+    //}
+    //
+    // if(*((uint32_t*)addr) == 0) return SOCKERR_IPINVALID;
+    if ((taddr == 0) && ((getSn_MR(sn) & Sn_MR_MACRAW) != Sn_MR_MACRAW))
+        return SOCKERR_IPINVALID;
+    if ((port == 0) && ((getSn_MR(sn) & Sn_MR_MACRAW) != Sn_MR_MACRAW))
+        return SOCKERR_PORTZERO;
+    tmp = getSn_SR(sn);
+    // #if ( _WIZCHIP_ < 5200 )
+    if ((tmp != SOCK_MACRAW) && (tmp != SOCK_UDP) && (tmp != SOCK_IPRAW))
+        return SOCKERR_SOCKSTATUS;
+    // #else
+    //    if(tmp != SOCK_MACRAW && tmp != SOCK_UDP) return SOCKERR_SOCKSTATUS;
+    // #endif
+
+    setSn_DIPR(sn, addr);
+    setSn_DPORT(sn, port);
+    freesize = getSn_TxMAX(sn);
+    if (len > freesize)
+        len = freesize; // check size not to exceed MAX size.
+    RyanWizchipCheckCode(1, 1000, 2, SOCKERR_SOCKCLOSED, {
+        freesize = getSn_TX_FSR(sn);
+        if (getSn_SR(sn) == SOCK_CLOSED)
+            return SOCKERR_SOCKCLOSED;
+        if ((sock_io_mode & (1 << sn)) && (len > freesize))
+            return SOCK_BUSY;
+        if (len <= freesize)
+            break;
+    });
+
+    wiz_send_data(sn, buf, len);
+
+#if _WIZCHIP_ < 5500 // M20150401 : for WIZCHIP Errata #4, #5 (ARP errata)
+    getSIPR((uint8_t *)&taddr);
+    if (taddr == 0)
+    {
+        getSUBR((uint8_t *)&taddr);
+        setSUBR((uint8_t *)"\x00\x00\x00\x00");
+    }
+    else
+        taddr = 0;
+#endif
+
+// A20150601 : For W5300
+#if _WIZCHIP_ == 5300
+    setSn_TX_WRSR(sn, len);
+#endif
+    //
+    setSn_CR(sn, Sn_CR_SEND);
+    /* wait to process the command... */
+    RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+
+    RyanWizchipCheckCode(1, 1000, 2, SOCKERR_SOCKCLOSED, {
+        tmp = getSn_IR(sn);
+        if (tmp & Sn_IR_SENDOK)
+        {
+            setSn_IR(sn, Sn_IR_SENDOK);
+            break;
+        }
+        // M:20131104
+        // else if(tmp & Sn_IR_TIMEOUT) return SOCKERR_TIMEOUT;
+        else if (tmp & Sn_IR_TIMEOUT)
+        {
+            setSn_IR(sn, Sn_IR_TIMEOUT);
+// M20150409 : Fixed the lost of sign bits by type casting.
+// len = (uint16_t)SOCKERR_TIMEOUT;
+// break;
+#if _WIZCHIP_ < 5500 // M20150401 : for WIZCHIP Errata #4, #5 (ARP errata)
+            if (taddr)
+                setSUBR((uint8_t *)&taddr);
+#endif
+            return SOCKERR_TIMEOUT;
+        }
+    });
+
+#if _WIZCHIP_ < 5500 // M20150401 : for WIZCHIP Errata #4, #5 (ARP errata)
+    if (taddr)
+        setSUBR((uint8_t *)&taddr);
+#endif
+    // M20150409 : Explicit Type Casting
+    // return len;
+    return (int32_t)len;
+}
+
+int32_t wizchip_recvfrom(uint8_t sn, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t *port)
+{
+// M20150601 : For W5300
+#if _WIZCHIP_ == 5300
+    uint16_t mr;
+    uint16_t mr1;
+#else
+    uint8_t mr;
+#endif
+    //
+    uint8_t head[8];
+    uint16_t pack_len = 0;
+
+    CHECK_SOCKNUM();
+    // CHECK_SOCKMODE(Sn_MR_UDP);
+// A20150601
+#if _WIZCHIP_ == 5300
+    mr1 = getMR();
+#endif
+
+    switch ((mr = getSn_MR(sn)) & 0x0F)
+    {
+    case Sn_MR_UDP:
+    case Sn_MR_IPRAW:
+    case Sn_MR_MACRAW:
+        break;
+#if (_WIZCHIP_ < 5200)
+    case Sn_MR_PPPoE:
+        break;
+#endif
+    default:
+        return SOCKERR_SOCKMODE;
+    }
+    CHECK_SOCKDATA();
+    if (sock_remained_size[sn] == 0)
+    {
+        RyanWizchipCheckCode(1, 1000, 1, SOCKERR_SOCKCLOSED, {
+            pack_len = getSn_RX_RSR(sn);
+            if (getSn_SR(sn) == SOCK_CLOSED)
+                return SOCKERR_SOCKCLOSED;
+            if ((sock_io_mode & (1 << sn)) && (pack_len == 0))
+                return SOCK_BUSY;
+            if (pack_len != 0)
+                break;
+        });
+    }
+    // D20150601 : Move it to bottom
+    //  sock_pack_info[sn] = PACK_COMPLETED;
+    switch (mr & 0x07)
+    {
+    case Sn_MR_UDP:
+        if (sock_remained_size[sn] == 0)
+        {
+            wiz_recv_data(sn, head, 8);
+            setSn_CR(sn, Sn_CR_RECV);
+            RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+
+            // read peer's IP address, port number & packet length
+            // A20150601 : For W5300
+#if _WIZCHIP_ == 5300
+            if (mr1 & MR_FS)
+            {
+                addr[0] = head[1];
+                addr[1] = head[0];
+                addr[2] = head[3];
+                addr[3] = head[2];
+                *port = head[5];
+                *port = (*port << 8) + head[4];
+                sock_remained_size[sn] = head[7];
+                sock_remained_size[sn] = (sock_remained_size[sn] << 8) + head[6];
+            }
+            else
+            {
+#endif
+                addr[0] = head[0];
+                addr[1] = head[1];
+                addr[2] = head[2];
+                addr[3] = head[3];
+                *port = head[4];
+                *port = (*port << 8) + head[5];
+                sock_remained_size[sn] = head[6];
+                sock_remained_size[sn] = (sock_remained_size[sn] << 8) + head[7];
+#if _WIZCHIP_ == 5300
+            }
+#endif
+            sock_pack_info[sn] = PACK_FIRST;
+        }
+        if (len < sock_remained_size[sn])
+            pack_len = len;
+        else
+            pack_len = sock_remained_size[sn];
+        // A20150601 : For W5300
+        len = pack_len;
+#if _WIZCHIP_ == 5300
+        if (sock_pack_info[sn] & PACK_FIFOBYTE)
+        {
+            *buf++ = sock_remained_byte[sn];
+            pack_len -= 1;
+            sock_remained_size[sn] -= 1;
+            sock_pack_info[sn] &= ~PACK_FIFOBYTE;
+        }
+#endif
+        //
+        // Need to packet length check (default 1472)
+        //
+        wiz_recv_data(sn, buf, pack_len); // data copy.
+        break;
+    case Sn_MR_MACRAW:
+        if (sock_remained_size[sn] == 0)
+        {
+            wiz_recv_data(sn, head, 2);
+            setSn_CR(sn, Sn_CR_RECV);
+            RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+
+            // read peer's IP address, port number & packet length
+            sock_remained_size[sn] = head[0];
+            sock_remained_size[sn] = (sock_remained_size[sn] << 8) + head[1] - 2;
+#if _WIZCHIP_ == W5300
+            if (sock_remained_size[sn] & 0x01)
+                sock_remained_size[sn] = sock_remained_size[sn] + 1 - 4;
+            else
+                sock_remained_size[sn] -= 4;
+#endif
+            if (sock_remained_size[sn] > 1514)
+            {
+                wizchip_close(sn);
+                return SOCKFATAL_PACKLEN;
+            }
+            sock_pack_info[sn] = PACK_FIRST;
+        }
+        if (len < sock_remained_size[sn])
+            pack_len = len;
+        else
+            pack_len = sock_remained_size[sn];
+        wiz_recv_data(sn, buf, pack_len);
+        break;
+        // #if ( _WIZCHIP_ < 5200 )
+    case Sn_MR_IPRAW:
+        if (sock_remained_size[sn] == 0)
+        {
+            wiz_recv_data(sn, head, 6);
+            setSn_CR(sn, Sn_CR_RECV);
+            RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+
+            addr[0] = head[0];
+            addr[1] = head[1];
+            addr[2] = head[2];
+            addr[3] = head[3];
+            sock_remained_size[sn] = head[4];
+            // M20150401 : For Typing Error
+            // sock_remaiend_size[sn] = (sock_remained_size[sn] << 8) + head[5];
+            sock_remained_size[sn] = (sock_remained_size[sn] << 8) + head[5];
+            sock_pack_info[sn] = PACK_FIRST;
+        }
+        //
+        // Need to packet length check
+        //
+        if (len < sock_remained_size[sn])
+            pack_len = len;
+        else
+            pack_len = sock_remained_size[sn];
+        wiz_recv_data(sn, buf, pack_len); // data copy.
+        break;
+        // #endif
+    default:
+        wiz_recv_ignore(sn, pack_len); // data copy.
+        sock_remained_size[sn] = pack_len;
+        break;
+    }
+    setSn_CR(sn, Sn_CR_RECV);
+    /* wait to process the command... */
+    RyanWizchipCheck(getSn_CR(sn), 10, SOCKERR_SOCKCLOSED);
+    sock_remained_size[sn] -= pack_len;
+    // M20150601 :
+    // if(sock_remained_size[sn] != 0) sock_pack_info[sn] |= 0x01;
+    if (sock_remained_size[sn] != 0)
+    {
+        sock_pack_info[sn] |= PACK_REMAINED;
+#if _WIZCHIP_ == 5300
+        if (pack_len & 0x01)
+            sock_pack_info[sn] |= PACK_FIFOBYTE;
+#endif
+    }
+    else
+        sock_pack_info[sn] = PACK_COMPLETED;
+#if _WIZCHIP_ == 5300
+    pack_len = len;
+#endif
+    //
+    // M20150409 : Explicit Type Casting
+    // return pack_len;
+    return (int32_t)pack_len;
+}
+
+int8_t ctlsocket(uint8_t sn, ctlsock_type cstype, void *arg)
+{
+    uint8_t tmp = 0;
+    CHECK_SOCKNUM();
+    switch (cstype)
+    {
+    case CS_SET_IOMODE:
+        tmp = *((uint8_t *)arg);
+        if (tmp == SOCK_IO_NONBLOCK)
+            sock_io_mode |= (1 << sn);
+        else if (tmp == SOCK_IO_BLOCK)
+            sock_io_mode &= ~(1 << sn);
+        else
+            return SOCKERR_ARG;
+        break;
+    case CS_GET_IOMODE:
+        // M20140501 : implict type casting -> explict type casting
+        //*((uint8_t*)arg) = (sock_io_mode >> sn) & 0x0001;
+        *((uint8_t *)arg) = (uint8_t)((sock_io_mode >> sn) & 0x0001);
+        //
+        break;
+    case CS_GET_MAXTXBUF:
+        *((uint16_t *)arg) = getSn_TxMAX(sn);
+        break;
+    case CS_GET_MAXRXBUF:
+        *((uint16_t *)arg) = getSn_RxMAX(sn);
+        break;
+    case CS_CLR_INTERRUPT:
+        if ((*(uint8_t *)arg) > SIK_ALL)
+            return SOCKERR_ARG;
+        setSn_IR(sn, *(uint8_t *)arg);
+        break;
+    case CS_GET_INTERRUPT:
+        *((uint8_t *)arg) = getSn_IR(sn);
+        break;
+#if _WIZCHIP_ != 5100
+    case CS_SET_INTMASK:
+        if ((*(uint8_t *)arg) > SIK_ALL)
+            return SOCKERR_ARG;
+        setSn_IMR(sn, *(uint8_t *)arg);
+        break;
+    case CS_GET_INTMASK:
+        *((uint8_t *)arg) = getSn_IMR(sn);
+        break;
+#endif
+    default:
+        return SOCKERR_ARG;
+    }
+    return SOCK_OK;
+}
+
+int8_t wizchip_setsockopt(uint8_t sn, sockopt_type sotype, void *arg)
+{
+    // M20131220 : Remove warning
+    // uint8_t tmp;
+    CHECK_SOCKNUM();
+    switch (sotype)
+    {
+    case SO_TTL:
+        setSn_TTL(sn, *(uint8_t *)arg);
+        break;
+    case SO_TOS:
+        setSn_TOS(sn, *(uint8_t *)arg);
+        break;
+    case SO_MSS:
+        setSn_MSSR(sn, *(uint16_t *)arg);
+        break;
+    case SO_DESTIP:
+        setSn_DIPR(sn, (uint8_t *)arg);
+        break;
+    case SO_DESTPORT:
+        setSn_DPORT(sn, *(uint16_t *)arg);
+        break;
+#if _WIZCHIP_ != 5100
+    case SO_KEEPALIVESEND:
+        CHECK_SOCKMODE(Sn_MR_TCP);
+#if _WIZCHIP_ > 5200
+        if (getSn_KPALVTR(sn) != 0)
+            return SOCKERR_SOCKOPT;
+#endif
+        setSn_CR(sn, Sn_CR_SEND_KEEP);
+
+        RyanWizchipCheckCode(getSn_CR(sn) != 0, 1000, 2, SOCKERR_SOCKCLOSED, {
+            // M20131220
+            // if ((tmp = getSn_IR(sn)) & Sn_IR_TIMEOUT)
+            if (getSn_IR(sn) & Sn_IR_TIMEOUT)
+            {
+                setSn_IR(sn, Sn_IR_TIMEOUT);
+                return SOCKERR_TIMEOUT;
+            }
+        });
+
+        break;
+#if !((_WIZCHIP_ == 5100) || (_WIZCHIP_ == 5200))
+    case SO_KEEPALIVEAUTO:
+        CHECK_SOCKMODE(Sn_MR_TCP);
+        setSn_KPALVTR(sn, *(uint8_t *)arg);
+        break;
+#endif
+#endif
+    default:
+        return SOCKERR_ARG;
+    }
+    return SOCK_OK;
+}
+
+int8_t wizchip_getsockopt(uint8_t sn, sockopt_type sotype, void *arg)
+{
+    CHECK_SOCKNUM();
+    switch (sotype)
+    {
+    case SO_FLAG:
+        *(uint8_t *)arg = getSn_MR(sn) & 0xF0;
+        break;
+    case SO_TTL:
+        *(uint8_t *)arg = getSn_TTL(sn);
+        break;
+    case SO_TOS:
+        *(uint8_t *)arg = getSn_TOS(sn);
+        break;
+    case SO_MSS:
+        *(uint16_t *)arg = getSn_MSSR(sn);
+        break;
+    case SO_DESTIP:
+        getSn_DIPR(sn, (uint8_t *)arg);
+        break;
+    case SO_DESTPORT:
+        *(uint16_t *)arg = getSn_DPORT(sn);
+        break;
+#if _WIZCHIP_ > 5200
+    case SO_KEEPALIVEAUTO:
+        CHECK_SOCKMODE(Sn_MR_TCP);
+        *(uint16_t *)arg = getSn_KPALVTR(sn);
+        break;
+#endif
+    case SO_SENDBUF:
+        *(uint16_t *)arg = getSn_TX_FSR(sn);
+        break;
+    case SO_RECVBUF:
+        *(uint16_t *)arg = getSn_RX_RSR(sn);
+        break;
+    case SO_STATUS:
+        *(uint8_t *)arg = getSn_SR(sn);
+        break;
+    case SO_REMAINSIZE:
+        if (getSn_MR(sn) & Sn_MR_TCP)
+            *(uint16_t *)arg = getSn_RX_RSR(sn);
+        else
+            *(uint16_t *)arg = sock_remained_size[sn];
+        break;
+    case SO_PACKINFO:
+        // CHECK_SOCKMODE(Sn_MR_TCP);
+#if _WIZCHIP_ != 5300
+        if ((getSn_MR(sn) == Sn_MR_TCP))
+            return SOCKERR_SOCKMODE;
+#endif
+        *(uint8_t *)arg = sock_pack_info[sn];
+        break;
+    default:
+        return SOCKERR_SOCKOPT;
+    }
+    return SOCK_OK;
+}

+ 488 - 0
ioLibrary/wizchip/wizchip_socket.h

@@ -0,0 +1,488 @@
+//*****************************************************************************
+//
+//! \file wizchip_socket.h
+//! \brief SOCKET APIs Header file.
+//! \details SOCKET APIs like as berkeley socket api.
+//! \version 1.0.2
+//! \date 2013/10/21
+//! \par  Revision history
+//!       <2015/02/05> Notice
+//!        The version history is not updated after this point.
+//!        Download the latest version directly from GitHub. Please visit the our GitHub repository for ioLibrary.
+//!        >> https://github.com/Wiznet/ioLibrary_Driver
+//!       <2014/05/01> V1.0.2. Refer to M20140501
+//!         1. Modify the comment : SO_REMAINED -> PACK_REMAINED
+//!         2. Add the comment as zero byte udp data reception in getsockopt().
+//!       <2013/10/21> 1st Release
+//! \author MidnightCow
+//! \copyright
+//!
+//! Copyright (c)  2013, WIZnet Co., LTD.
+//! All rights reserved.
+//!
+//! Redistribution and use in source and binary forms, with or without
+//! modification, are permitted provided that the following conditions
+//! are met:
+//!
+//!     * Redistributions of source code must retain the above copyright
+//! notice, this list of conditions and the following disclaimer.
+//!     * Redistributions in binary form must reproduce the above copyright
+//! notice, this list of conditions and the following disclaimer in the
+//! documentation and/or other materials provided with the distribution.
+//!     * Neither the name of the <ORGANIZATION> nor the names of its
+//! contributors may be used to endorse or promote products derived
+//! from this software without specific prior written permission.
+//!
+//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+//! THE POSSIBILITY OF SUCH DAMAGE.
+//
+//*****************************************************************************
+/**
+ * @defgroup WIZnet_socket_APIs 1. WIZnet socket APIs
+ * @brief WIZnet socket APIs are based on Berkeley socket APIs,  thus it has much similar name and interface.
+ *        But there is a little bit of difference.
+ * @details
+ * <b> Comparison between WIZnet and Berkeley SOCKET APIs </b>
+ * <table>
+ *    <tr>   <td><b>API</b></td> <td><b>WIZnet</b></td> <td><b>Berkeley</b></td>   </tr>
+ *    <tr>   <td>socket()</td> <td>O</td> <td>O</td>   </tr>
+ *    <tr>   <td><b>bind()</b></td> <td>X</td> <td>O</td>   </tr>
+ *    <tr>   <td><b>listen()</b></td> <td>O</td> <td>O</td>   </tr>
+ *    <tr>   <td><b>connect()</b></td> <td>O</td> <td>O</td>   </tr>
+ *    <tr>   <td><b>accept()</b></td> <td>X</td> <td>O</td>   </tr>
+ *    <tr>   <td><b>recv()</b></td> <td>O</td> <td>O</td>    </tr>
+ *    <tr>   <td><b>send()</b></td> <td>O</td> <td>O</td>   </tr>
+ *    <tr>   <td><b>recvfrom()</b></td> <td>O</td> <td>O</td>   </tr>
+ *    <tr>   <td><b>sendto()</b></td> <td>O</td> <td>O</td>    </tr>
+ *    <tr>   <td><b>closesocket()</b></td> <td>O<br>close() & disconnect()</td> <td>O</td>   </tr>
+ * </table>
+ * There are @b bind() and @b accept() functions in @b Berkeley SOCKET API but,
+ * not in @b WIZnet SOCKET API. Because socket() of WIZnet is not only creating a SOCKET but also binding a local port number,
+ * and listen() of WIZnet is not only listening to connection request from client but also accepting the connection request. \n
+ * When you program "TCP SERVER" with Berkeley SOCKET API, you can use only one listen port.
+ * When the listen SOCKET accepts a connection request from a client, it keeps listening.
+ * After accepting the connection request, a new SOCKET is created and the new SOCKET is used in communication with the client. \n
+ * Following figure shows network flow diagram by Berkeley SOCKET API.
+ * @image html Berkeley_SOCKET.jpg "<Berkeley SOCKET API>"
+ * But, When you program "TCP SERVER" with WIZnet SOCKET API, you can use as many as 8 listen SOCKET with same port number. \n
+ * Because there's no accept() in WIZnet SOCKET APIs, when the listen SOCKET accepts a connection request from a client,
+ * it is changed in order to communicate with the client.
+ * And the changed SOCKET is not listening any more and is dedicated for communicating with the client. \n
+ * If there're many listen SOCKET with same listen port number and a client requests a connection,
+ * the SOCKET which has the smallest SOCKET number accepts the request and is changed as communication SOCKET. \n
+ * Following figure shows network flow diagram by WIZnet SOCKET API.
+ * @image html WIZnet_SOCKET.jpg "<WIZnet SOCKET API>"
+ */
+#ifndef _WIZCHIP_SOCKET_H_
+#define _WIZCHIP_SOCKET_H_
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "wizchip_conf.h"
+
+#define SOCKET uint8_t // SOCKET type define for legacy driver
+
+#define SOCK_OK 1        // Result is OK about socket process.
+#define SOCK_BUSY 0      // Socket is busy on processing the operation. Valid only Non-block IO Mode.
+#define SOCK_FATAL -1000 // Result is fatal error about socket process.
+
+#define SOCK_ERROR 0
+#define SOCKERR_SOCKNUM (SOCK_ERROR - 1)    // Invalid socket number
+#define SOCKERR_SOCKOPT (SOCK_ERROR - 2)    // Invalid socket option
+#define SOCKERR_SOCKINIT (SOCK_ERROR - 3)   // Socket is not initialized or SIPR is Zero IP address when Sn_MR_TCP
+#define SOCKERR_SOCKCLOSED (SOCK_ERROR - 4) // Socket unexpectedly closed.
+#define SOCKERR_SOCKMODE (SOCK_ERROR - 5)   // Invalid socket mode for socket operation.
+#define SOCKERR_SOCKFLAG (SOCK_ERROR - 6)   // Invalid socket flag
+#define SOCKERR_SOCKSTATUS (SOCK_ERROR - 7) // Invalid socket status for socket operation.
+#define SOCKERR_ARG (SOCK_ERROR - 10)       // Invalid argument.
+#define SOCKERR_PORTZERO (SOCK_ERROR - 11)  // Port number is zero
+#define SOCKERR_IPINVALID (SOCK_ERROR - 12) // Invalid IP address
+#define SOCKERR_TIMEOUT (SOCK_ERROR - 13)   // Timeout occurred
+#define SOCKERR_DATALEN (SOCK_ERROR - 14)   // Data length is zero or greater than buffer max size.
+#define SOCKERR_BUFFER (SOCK_ERROR - 15)    // Socket buffer is not enough for data communication.
+
+#define SOCKFATAL_PACKLEN (SOCK_FATAL - 1) // Invalid packet length. Fatal Error.
+
+/*
+ * SOCKET FLAG
+ */
+#define SF_ETHER_OWN (Sn_MR_MFEN)     // In @ref Sn_MR_MACRAW, Receive only the packet as broadcast, multicast and own packet
+#define SF_IGMP_VER2 (Sn_MR_MC)       // In @ref Sn_MR_UDP with \ref SF_MULTI_ENABLE, Select IGMP version 2.
+#define SF_TCP_NODELAY (Sn_MR_ND)     // In @ref Sn_MR_TCP, Use to nodelayed ack.
+#define SF_MULTI_ENABLE (Sn_MR_MULTI) // In @ref Sn_MR_UDP, Enable multicast mode.
+
+#if _WIZCHIP_ == 5500
+#define SF_BROAD_BLOCK (Sn_MR_BCASTB) // In @ref Sn_MR_UDP or @ref Sn_MR_MACRAW, Block broadcast packet. Valid only in W5500
+#define SF_MULTI_BLOCK (Sn_MR_MMB)    // In @ref Sn_MR_MACRAW, Block multicast packet. Valid only in W5500
+#define SF_IPv6_BLOCK (Sn_MR_MIP6B)   // In @ref Sn_MR_MACRAW, Block IPv6 packet. Valid only in W5500
+#define SF_UNI_BLOCK (Sn_MR_UCASTB)   // In @ref Sn_MR_UDP with \ref SF_MULTI_ENABLE. Valid only in W5500
+#endif
+
+// A201505 : For W5300
+#if _WIZCHIP_ == 5300
+#define SF_TCP_ALIGN 0x02 // Valid only \ref Sn_MR_TCP and W5300, refer to \ref Sn_MR_ALIGN
+#endif
+
+#define SF_IO_NONBLOCK 0x01 // Socket nonblock io mode. It used parameter in \ref socket().
+
+/*
+ * UDP & MACRAW Packet Infomation
+ */
+#define PACK_FIRST 0x80     // In Non-TCP packet, It indicates to start receiving a packet. (When W5300, This flag can be applied)
+#define PACK_REMAINED 0x01  // In Non-TCP packet, It indicates to remain a packet to be received. (When W5300, This flag can be applied)
+#define PACK_COMPLETED 0x00 // In Non-TCP packet, It indicates to complete to receive a packet. (When W5300, This flag can be applied)
+// A20150601 : For Integrating with W5300
+#define PACK_FIFOBYTE 0x02 // bbbb Valid only W5300, It indicate to have read already the Sn_RX_FIFOR.
+    //
+
+    /**
+     * @ingroup WIZnet_socket_APIs
+     * @brief Open a socket.
+     * @details Initializes the socket with 'sn' passed as parameter and open.
+     *
+     * @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
+     * @param protocol Protocol type to operate such as TCP, UDP and MACRAW.
+     * @param port Port number to be bined.
+     * @param flag Socket flags as \ref SF_ETHER_OWN, \ref SF_IGMP_VER2, \ref SF_TCP_NODELAY, \ref SF_MULTI_ENABLE, \ref SF_IO_NONBLOCK and so on.\n
+     *             Valid flags only in W5500 : @ref SF_BROAD_BLOCK, @ref SF_MULTI_BLOCK, @ref SF_IPv6_BLOCK, and @ref SF_UNI_BLOCK.
+     * @sa Sn_MR
+     *
+     * @return @b Success : The socket number @b 'sn' passed as parameter\n
+     *         @b Fail    :\n @ref SOCKERR_SOCKNUM     - Invalid socket number\n
+     *                        @ref SOCKERR_SOCKMODE    - Not support socket mode as TCP, UDP, and so on. \n
+     *                        @ref SOCKERR_SOCKFLAG    - Invaild socket flag.
+     */
+    int8_t wizchip_socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag);
+
+    /**
+     * @ingroup WIZnet_socket_APIs
+     * @brief Close a socket.
+     * @details It closes the socket  with @b'sn' passed as parameter.
+     *
+     * @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
+     *
+     * @return @b Success : @ref SOCK_OK \n
+     *         @b Fail    : @ref SOCKERR_SOCKNUM - Invalid socket number
+     */
+    int8_t wizchip_close(uint8_t sn);
+
+    /**
+     * @ingroup WIZnet_socket_APIs
+     * @brief Listen to a connection request from a client.
+     * @details It is listening to a connection request from a client.
+     * If connection request is accepted successfully, the connection is established. Socket sn is used in passive(server) mode.
+     *
+     * @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
+     * @return @b Success : @ref SOCK_OK \n
+     *         @b Fail    :\n @ref SOCKERR_SOCKINIT   - Socket is not initialized \n
+     *                        @ref SOCKERR_SOCKCLOSED - Socket closed unexpectedly.
+     */
+    int8_t wizchip_listen(uint8_t sn);
+
+    /**
+     * @ingroup WIZnet_socket_APIs
+     * @brief Try to connect a server.
+     * @details It requests connection to the server with destination IP address and port number passed as parameter.\n
+     * @note It is valid only in TCP client mode.
+     *       In block io mode, it does not return until connection is completed.
+     *       In Non-block io mode, it return @ref SOCK_BUSY immediately.
+     *
+     * @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
+     * @param addr Pointer variable of destination IP address. It should be allocated 4 bytes.
+     * @param port Destination port number.
+     *
+     * @return @b Success : @ref SOCK_OK \n
+     * @b Fail    :\n @ref SOCKERR_SOCKNUM   - Invalid socket number\n
+     *                @ref SOCKERR_SOCKMODE  - Invalid socket mode\n
+     *                @ref SOCKERR_SOCKINIT  - Socket is not initialized\n
+     *                @ref SOCKERR_IPINVALID - Wrong server IP address\n
+     *                @ref SOCKERR_PORTZERO  - Server port zero\n
+     *                @ref SOCKERR_TIMEOUT   - Timeout occurred during request connection\n
+     *                @ref SOCK_BUSY         - In non-block io mode, it returned immediately\n
+     */
+    int8_t wizchip_connect(uint8_t sn, uint8_t *addr, uint16_t port);
+
+    /**
+     * @ingroup WIZnet_socket_APIs
+     * @brief Try to disconnect a connection socket.
+     * @details It sends request message to disconnect the TCP socket 'sn' passed as parameter to the server or client.
+     * @note It is valid only in TCP server or client mode. \n
+     *       In block io mode, it does not return until disconnection is completed. \n
+     *       In Non-block io mode, it return @ref SOCK_BUSY immediately. \n
+
+     * @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
+     * @return @b Success :   @ref SOCK_OK \n
+     *         @b Fail    :\n @ref SOCKERR_SOCKNUM  - Invalid socket number \n
+     *                        @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n
+     *                        @ref SOCKERR_TIMEOUT  - Timeout occurred \n
+     *                        @ref SOCK_BUSY        - Socket is busy.
+     */
+    int8_t wizchip_disconnect(uint8_t sn);
+
+    /**
+     * @ingroup WIZnet_socket_APIs
+     * @brief	Send data to the connected peer in TCP socket.
+     * @details It is used to send outgoing data to the connected socket.
+     * @note    It is valid only in TCP server or client mode. It can't send data greater than socket buffer size. \n
+     *          In block io mode, It doesn't return until data send is completed - socket buffer size is greater than data. \n
+     *          In non-block io mode, It return @ref SOCK_BUSY immediately when socket buffer is not enough. \n
+     * @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
+     * @param buf Pointer buffer containing data to be sent.
+     * @param len The byte length of data in buf.
+     * @return	@b Success : The sent data size \n
+     *          @b Fail    : \n @ref SOCKERR_SOCKSTATUS - Invalid socket status for socket operation \n
+     *                          @ref SOCKERR_TIMEOUT    - Timeout occurred \n
+     *                          @ref SOCKERR_SOCKMODE 	- Invalid operation in the socket \n
+     *                          @ref SOCKERR_SOCKNUM    - Invalid socket number \n
+     *                          @ref SOCKERR_DATALEN    - zero data length \n
+     *                          @ref SOCK_BUSY          - Socket is busy.
+     */
+    int32_t wizchip_send(uint8_t sn, uint8_t *buf, uint16_t len);
+
+    /**
+     * @ingroup WIZnet_socket_APIs
+     * @brief	Receive data from the connected peer.
+     * @details It is used to read incoming data from the connected socket.\n
+     *          It waits for data as much as the application wants to receive.
+     * @note    It is valid only in TCP server or client mode. It can't receive data greater than socket buffer size. \n
+     *          In block io mode, it doesn't return until data reception is completed - data is filled as <I>len</I> in socket buffer. \n
+     *          In non-block io mode, it return @ref SOCK_BUSY immediately when <I>len</I> is greater than data size in socket buffer. \n
+     *
+     * @param sn  Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
+     * @param buf Pointer buffer to read incoming data.
+     * @param len The max data length of data in buf.
+     * @return	@b Success : The real received data size \n
+     *          @b Fail    :\n
+     *                     @ref SOCKERR_SOCKSTATUS - Invalid socket status for socket operation \n
+     *                     @ref SOCKERR_SOCKMODE   - Invalid operation in the socket \n
+     *                     @ref SOCKERR_SOCKNUM    - Invalid socket number \n
+     *                     @ref SOCKERR_DATALEN    - zero data length \n
+     *                     @ref SOCK_BUSY          - Socket is busy.
+     */
+    int32_t wizchip_recv(uint8_t sn, uint8_t *buf, uint16_t len);
+
+    /**
+     * @ingroup WIZnet_socket_APIs
+     * @brief	Sends datagram to the peer with destination IP address and port number passed as parameter.
+     * @details It sends datagram of UDP or MACRAW to the peer with destination IP address and port number passed as parameter.\n
+     *          Even if the connectionless socket has been previously connected to a specific address,
+     *          the address and port number parameters override the destination address for that particular datagram only.
+     * @note    In block io mode, It doesn't return until data send is completed - socket buffer size is greater than <I>len</I>.
+     *          In non-block io mode, It return @ref SOCK_BUSY immediately when socket buffer is not enough.
+     *
+     * @param sn    Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
+     * @param buf   Pointer buffer to send outgoing data.
+     * @param len   The byte length of data in buf.
+     * @param addr  Pointer variable of destination IP address. It should be allocated 4 bytes.
+     * @param port  Destination port number.
+     *
+     * @return @b Success : The sent data size \n
+     *         @b Fail    :\n @ref SOCKERR_SOCKNUM     - Invalid socket number \n
+     *                        @ref SOCKERR_SOCKMODE    - Invalid operation in the socket \n
+     *                        @ref SOCKERR_SOCKSTATUS  - Invalid socket status for socket operation \n
+     *                        @ref SOCKERR_DATALEN     - zero data length \n
+     *                        @ref SOCKERR_IPINVALID   - Wrong server IP address\n
+     *                        @ref SOCKERR_PORTZERO    - Server port zero\n
+     *                        @ref SOCKERR_SOCKCLOSED  - Socket unexpectedly closed \n
+     *                        @ref SOCKERR_TIMEOUT     - Timeout occurred \n
+     *                        @ref SOCK_BUSY           - Socket is busy.
+     */
+    int32_t wizchip_sendto(uint8_t sn, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t port);
+
+    /**
+     * @ingroup WIZnet_socket_APIs
+     * @brief Receive datagram of UDP or MACRAW
+     * @details This function is an application I/F function which is used to receive the data in other then TCP mode. \n
+     *          This function is used to receive UDP and MAC_RAW mode, and handle the header as well.
+     *          This function can divide to received the packet data.
+     *          On the MACRAW SOCKET, the addr and port parameters are ignored.
+     * @note    In block io mode, it doesn't return until data reception is completed - data is filled as <I>len</I> in socket buffer
+     *          In non-block io mode, it return @ref SOCK_BUSY immediately when <I>len</I> is greater than data size in socket buffer.
+     *
+     * @param sn   Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
+     * @param buf  Pointer buffer to read incoming data.
+     * @param len  The max data length of data in buf.
+     *             When the received packet size <= len, receives data as packet sized.
+     *             When others, receives data as len.
+     * @param addr Pointer variable of destination IP address. It should be allocated 4 bytes.
+     *             It is valid only when the first call recvfrom for receiving the packet.
+     *             When it is valid, @ref  packinfo[7] should be set as '1' after call @ref getsockopt(sn, SO_PACKINFO, &packinfo).
+     * @param port Pointer variable of destination port number.
+     *             It is valid only when the first call recvform for receiving the packet.
+     *             When it is valid, @ref  packinfo[7] should be set as '1' after call @ref getsockopt(sn, SO_PACKINFO, &packinfo).
+     *
+     * @return	@b Success : This function return real received data size for success.\n
+     *          @b Fail    : @ref SOCKERR_DATALEN    - zero data length \n
+     *                       @ref SOCKERR_SOCKMODE   - Invalid operation in the socket \n
+     *                       @ref SOCKERR_SOCKNUM    - Invalid socket number \n
+     *                       @ref SOCKBUSY           - Socket is busy.
+     */
+    int32_t wizchip_recvfrom(uint8_t sn, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t *port);
+
+/////////////////////////////
+// SOCKET CONTROL & OPTION //
+/////////////////////////////
+#define SOCK_IO_BLOCK 0    // Socket Block IO Mode in @ref setsockopt().
+#define SOCK_IO_NONBLOCK 1 // Socket Non-block IO Mode in @ref setsockopt().
+
+    /**
+     * @defgroup DATA_TYPE DATA TYPE
+     */
+
+    /**
+     * @ingroup DATA_TYPE
+     * @brief The kind of Socket Interrupt.
+     * @sa Sn_IR, Sn_IMR, setSn_IR(), getSn_IR(), setSn_IMR(), getSn_IMR()
+     */
+    typedef enum
+    {
+        SIK_CONNECTED = (1 << 0),    // connected
+        SIK_DISCONNECTED = (1 << 1), // disconnected
+        SIK_RECEIVED = (1 << 2),     // data received
+        SIK_TIMEOUT = (1 << 3),      // timeout occurred
+        SIK_SENT = (1 << 4),         // send ok
+        // M20150410 : Remove the comma of last member
+        // SIK_ALL           = 0x1F,        // all interrupt
+        SIK_ALL = 0x1F // all interrupt
+    } sockint_kind;
+
+    /**
+     * @ingroup DATA_TYPE
+     * @brief The type of @ref ctlsocket().
+     */
+    typedef enum
+    {
+        CS_SET_IOMODE,    // set socket IO mode with @ref SOCK_IO_BLOCK or @ref SOCK_IO_NONBLOCK
+        CS_GET_IOMODE,    // get socket IO mode
+        CS_GET_MAXTXBUF,  // get the size of socket buffer allocated in TX memory
+        CS_GET_MAXRXBUF,  // get the size of socket buffer allocated in RX memory
+        CS_CLR_INTERRUPT, // clear the interrupt of socket with @ref sockint_kind
+        CS_GET_INTERRUPT, // get the socket interrupt. refer to @ref sockint_kind
+#if _WIZCHIP_ > 5100
+        CS_SET_INTMASK, // set the interrupt mask of socket with @ref sockint_kind, Not supported in W5100
+        CS_GET_INTMASK  // get the masked interrupt of socket. refer to @ref sockint_kind, Not supported in W5100
+#endif
+    } ctlsock_type;
+
+    /**
+     * @ingroup DATA_TYPE
+     * @brief The type of socket option in @ref setsockopt() or @ref getsockopt()
+     */
+    typedef enum
+    {
+        SO_FLAG,     // Valid only in getsockopt(), For set flag of socket refer to <I>flag</I> in @ref socket().
+        SO_TTL,      // Set TTL. @ref Sn_TTL  ( @ref setSn_TTL(), @ref getSn_TTL() )
+        SO_TOS,      // Set TOS. @ref Sn_TOS  ( @ref setSn_TOS(), @ref getSn_TOS() )
+        SO_MSS,      // Set MSS. @ref Sn_MSSR ( @ref setSn_MSSR(), @ref getSn_MSSR() )
+        SO_DESTIP,   // Set the destination IP address. @ref Sn_DIPR ( @ref setSn_DIPR(), @ref getSn_DIPR() )
+        SO_DESTPORT, // Set the destination Port number. @ref Sn_DPORT ( @ref setSn_DPORT(), @ref getSn_DPORT() )
+#if _WIZCHIP_ != 5100
+        SO_KEEPALIVESEND, // Valid only in setsockopt. Manually send keep-alive packet in TCP mode, Not supported in W5100
+#if !((_WIZCHIP_ == 5100) || (_WIZCHIP_ == 5200))
+        SO_KEEPALIVEAUTO, // Set/Get keep-alive auto transmission timer in TCP mode, Not supported in W5100, W5200
+#endif
+#endif
+        SO_SENDBUF,    // Valid only in getsockopt. Get the free data size of Socekt TX buffer. @ref Sn_TX_FSR, @ref getSn_TX_FSR()
+        SO_RECVBUF,    // Valid only in getsockopt. Get the received data size in socket RX buffer. @ref Sn_RX_RSR, @ref getSn_RX_RSR()
+        SO_STATUS,     // Valid only in getsockopt. Get the socket status. @ref Sn_SR, @ref getSn_SR()
+        SO_REMAINSIZE, // Valid only in getsockopt. Get the remained packet size in other then TCP mode.
+        SO_PACKINFO    // Valid only in getsockopt. Get the packet information as @ref PACK_FIRST, @ref PACK_REMAINED, and @ref PACK_COMPLETED in other then TCP mode.
+    } sockopt_type;
+
+    /**
+     * @ingroup WIZnet_socket_APIs
+     *  @brief Control socket.
+     *  @details Control IO mode, Interrupt & Mask of socket and get the socket buffer information.
+     *           Refer to @ref ctlsock_type.
+     *  @param sn socket number
+     *  @param cstype type of control socket. refer to @ref ctlsock_type.
+     *  @param arg Data type and value is determined according to @ref ctlsock_type. \n
+     *             <table>
+     *                  <tr> <td> @b cstype </td> <td> @b data type</td><td>@b value</td></tr>
+     *                  <tr> <td> @ref CS_SET_IOMODE \n @ref CS_GET_IOMODE </td> <td> uint8_t </td><td>@ref SOCK_IO_BLOCK @ref SOCK_IO_NONBLOCK</td></tr>
+     *                  <tr> <td> @ref CS_GET_MAXTXBUF \n @ref CS_GET_MAXRXBUF </td> <td> uint16_t </td><td> 0 ~ 16K </td></tr>
+     *                  <tr> <td> @ref CS_CLR_INTERRUPT \n @ref CS_GET_INTERRUPT \n @ref CS_SET_INTMASK \n @ref CS_GET_INTMASK </td> <td> @ref sockint_kind </td><td> @ref SIK_CONNECTED, etc.  </td></tr>
+     *             </table>
+     *  @return @b Success @ref SOCK_OK \n
+     *          @b fail    @ref SOCKERR_ARG         - Invalid argument\n
+     */
+    int8_t wizchip_ctlsocket(uint8_t sn, ctlsock_type cstype, void *arg);
+
+    /**
+     * @ingroup WIZnet_socket_APIs
+     *  @brief set socket options
+     *  @details Set socket option like as TTL, MSS, TOS, and so on. Refer to @ref sockopt_type.
+     *
+     *  @param sn socket number
+     *  @param sotype socket option type. refer to @ref sockopt_type
+     *  @param arg Data type and value is determined according to <I>sotype</I>. \n
+     *             <table>
+     *                  <tr> <td> @b sotype </td> <td> @b data type</td><td>@b value</td></tr>
+     *                  <tr> <td> @ref SO_TTL </td> <td> uint8_t </td><td> 0 ~ 255 </td> </tr>
+     *                  <tr> <td> @ref SO_TOS </td> <td> uint8_t </td><td> 0 ~ 255 </td> </tr>
+     *                  <tr> <td> @ref SO_MSS </td> <td> uint16_t </td><td> 0 ~ 65535 </td> </tr>
+     *                  <tr> <td> @ref SO_DESTIP </td> <td> uint8_t[4] </td><td>  </td></tr>
+     *                  <tr> <td> @ref SO_DESTPORT </td> <td> uint16_t </td><td> 0 ~ 65535 </td></tr>
+     *                  <tr> <td> @ref SO_KEEPALIVESEND </td> <td> null </td><td> null </td></tr>
+     *                  <tr> <td> @ref SO_KEEPALIVEAUTO </td> <td> uint8_t </td><td> 0 ~ 255 </td></tr>
+     *             </table>
+     * @return
+     * - @b Success : @ref SOCK_OK \n
+     * - @b Fail
+     *  - @ref SOCKERR_SOCKNUM     - Invalid Socket number \n
+     *  - @ref SOCKERR_SOCKMODE    - Invalid socket mode \n
+     *  - @ref SOCKERR_SOCKOPT     - Invalid socket option or its value \n
+     *  - @ref SOCKERR_TIMEOUT     - Timeout occurred when sending keep-alive packet \n
+     */
+    int8_t wizchip_setsockopt(uint8_t sn, sockopt_type sotype, void *arg);
+
+    /**
+     * @ingroup WIZnet_socket_APIs
+     *  @brief get socket options
+     *  @details Get socket option like as FLAG, TTL, MSS, and so on. Refer to @ref sockopt_type
+     *  @param sn socket number
+     *  @param sotype socket option type. refer to @ref sockopt_type
+     *  @param arg Data type and value is determined according to <I>sotype</I>. \n
+     *             <table>
+     *                  <tr> <td> @b sotype </td> <td>@b data type</td><td>@b value</td></tr>
+     *                  <tr> <td> @ref SO_FLAG </td> <td> uint8_t </td><td> @ref SF_ETHER_OWN, etc... </td> </tr>
+     *                  <tr> <td> @ref SO_TOS </td> <td> uint8_t </td><td> 0 ~ 255 </td> </tr>
+     *                  <tr> <td> @ref SO_MSS </td> <td> uint16_t </td><td> 0 ~ 65535 </td> </tr>
+     *                  <tr> <td> @ref SO_DESTIP </td> <td> uint8_t[4] </td><td>  </td></tr>
+     *                  <tr> <td> @ref SO_DESTPORT </td> <td> uint16_t </td><td>  </td></tr>
+     *                  <tr> <td> @ref SO_KEEPALIVEAUTO </td> <td> uint8_t </td><td> 0 ~ 255 </td></tr>
+     *                  <tr> <td> @ref SO_SENDBUF </td> <td> uint16_t </td><td> 0 ~ 65535 </td></tr>
+     *                  <tr> <td> @ref SO_RECVBUF </td> <td> uint16_t </td><td> 0 ~ 65535 </td></tr>
+     *                  <tr> <td> @ref SO_STATUS </td> <td> uint8_t </td><td> @ref SOCK_ESTABLISHED, etc.. </td></tr>
+     *                  <tr> <td> @ref SO_REMAINSIZE </td> <td> uint16_t </td><td> 0~ 65535 </td></tr>
+     *                  <tr> <td> @ref SO_PACKINFO </td> <td> uint8_t </td><td> @ref PACK_FIRST, etc... </td></tr>
+     *             </table>
+     * @return
+     * - @b Success : @ref SOCK_OK \n
+     * - @b Fail
+     *  - @ref SOCKERR_SOCKNUM     - Invalid Socket number \n
+     *  - @ref SOCKERR_SOCKOPT     - Invalid socket option or its value \n
+     *  - @ref SOCKERR_SOCKMODE    - Invalid socket mode \n
+     * @note
+     *   The option as PACK_REMAINED and SO_PACKINFO is valid only in NON-TCP mode and after call @ref recvfrom(). \n
+     *   When SO_PACKINFO value is PACK_FIRST and the return value of recvfrom() is zero,
+     *   This means the zero byte UDP data(UDP Header only) received.
+     */
+    int8_t wizchip_getsockopt(uint8_t sn, sockopt_type sotype, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _WIZCHIP_SOCKET_H_

+ 77 - 0
platform/RT-Thread/platformTimer.c

@@ -0,0 +1,77 @@
+
+
+#include "platformTimer.h"
+
+// Ryan别的包也有
+#define __weak __attribute__((weak)) // 防止函数重定义, gcc / ARM编译器有效  IAR可以注释此行
+
+/**
+ * @brief 自系统启动以来的毫秒时间戳
+ *
+ * @return uint32_t
+ */
+__weak uint32_t platformUptimeMs(void)
+{
+#if (RT_TICK_PER_SECOND == 1000)
+    return (uint32_t)rt_tick_get();
+#else
+    rt_tick_t tick = 0u;
+
+    tick = rt_tick_get() * 1000;
+    return (uint32_t)((tick + RT_TICK_PER_SECOND - 1) / RT_TICK_PER_SECOND);
+#endif
+}
+
+/**
+ * @brief 初始化定时器,没有使用,
+ * timer结构体比较简单,没有做init和destory。看后面需求
+ *
+ * @param platformTimer
+ */
+__weak void platformTimerInit(platformTimer_t *platformTimer)
+{
+    platformTimer->time = 0;
+    platformTimer->timeOut = 0;
+}
+
+/**
+ * @brief 添加计数时间
+ *
+ * @param platformTimer
+ * @param timeout
+ */
+__weak void platformTimerCutdown(platformTimer_t *platformTimer, uint32_t timeout)
+{
+    platformTimer->timeOut = timeout;
+    platformTimer->time = platformUptimeMs();
+}
+
+/**
+ * @brief 计算time还有多长时间超时,考虑了32位溢出判断
+ *
+ * @param platformTimer
+ * @return uint32_t 返回剩余时间,超时返回0
+ */
+__weak uint32_t platformTimerRemain(platformTimer_t *platformTimer)
+{
+    uint32_t tnow = platformUptimeMs();
+    uint32_t overTime = platformTimer->time + platformTimer->timeOut;
+    // uint32_t 没有溢出
+    if (overTime >= platformTimer->time)
+    {
+        // tnow溢出,不存在时间超时可能性
+        if (tnow < platformTimer->time)
+            return (UINT32_MAX - overTime + tnow + 1);
+
+        // tnow没有溢出
+        return tnow >= overTime ? 0 : (overTime - tnow);
+    }
+
+    // uint32_t 溢出了
+    // tnow 溢出了
+    if (tnow < platformTimer->time)
+        return tnow >= overTime ? 0 : (overTime - tnow + 1);
+
+    // tnow 没有溢出
+    return UINT32_MAX - tnow + overTime + 1;
+}

+ 32 - 0
platform/RT-Thread/platformTimer.h

@@ -0,0 +1,32 @@
+
+
+#ifndef __platformTimer__
+#define __platformTimer__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#include <rtthread.h>
+#include <stdint.h>
+
+    // 定义枚举类型
+
+    // 定义结构体类型
+    typedef struct
+    {
+        uint32_t time;
+        uint32_t timeOut;
+    } platformTimer_t;
+
+    /* extern variables-----------------------------------------------------------*/
+
+    extern uint32_t platformUptimeMs(void);
+    extern void platformTimerInit(platformTimer_t *platformTimer);
+    extern void platformTimerCutdown(platformTimer_t *platformTimer, uint32_t timeout);
+    extern uint32_t platformTimerRemain(platformTimer_t *platformTimer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 146 - 0
platform/RT-Thread/platformW5500Hardware.c

@@ -0,0 +1,146 @@
+#include "RyanApplication.h"
+
+static struct rt_spi_device *RyanW5500SpiDevice = NULL;
+#define RyanW5500SpiDeviceName "spi26"
+#define RyanW5500SpiFreqMax (40 * 1000 * 1000)
+
+#define RyanW5500ResetGpio GET_PIN(C, 0)
+#define RyanW5500IRQGpio GET_PIN(C, 1)
+
+/**
+ * @brief SPI 初始化
+ *
+ */
+int RyanW5500SpiInit()
+{
+    rt_hw_spi_device_attach("spi2", RyanW5500SpiDeviceName, GPIOE, GPIO_PIN_15);
+
+    RyanW5500SpiDevice = rt_device_find(RyanW5500SpiDeviceName);
+    if (RyanW5500SpiDevice == NULL)
+    {
+        LOG_E("You should attach [%s] into SPI bus firstly.", RyanW5500SpiDeviceName);
+        return RT_ERROR;
+    }
+
+    struct rt_spi_configuration cfg = {
+        .data_width = 8,
+        .mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB, //  SPI Compatible Modes 0
+        .max_hz = RyanW5500SpiFreqMax                       // SPI Interface with Clock Speeds Up to 40 MHz
+    };
+    rt_spi_configure(RyanW5500SpiDevice, &cfg);
+
+    if (rt_device_open(RyanW5500SpiDevice, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
+    {
+        LOG_E("open WIZnet SPI device %s error.", RyanW5500SpiDeviceName);
+        return RT_ERROR;
+    }
+
+    return RT_EOK;
+}
+
+/**
+ * @brief SPI 写入一个字节
+ *
+ * @param data
+ */
+void RyanW5500WriteByte(uint8_t data)
+{
+    struct rt_spi_message spiMsg = {
+        .send_buf = &data,
+        .length = 1};
+
+    rt_spi_transfer_message(RyanW5500SpiDevice, &spiMsg);
+}
+
+/**
+ * @brief SPI 读取一个字节
+ *
+ * @return uint8_t
+ */
+uint8_t RyanW5500ReadByte(void)
+{
+    uint8_t data;
+    struct rt_spi_message spiMsg = {
+        .recv_buf = &data,
+        .length = 1};
+
+    rt_spi_transfer_message(RyanW5500SpiDevice, &spiMsg);
+
+    return data;
+}
+
+/**
+ * @brief SPI 写入多个字节
+ *
+ * @param pbuf
+ * @param len
+ */
+void RyanW5500WriteBurst(uint8_t *pbuf, uint16_t len)
+{
+    struct rt_spi_message spiMsg = {
+        .send_buf = pbuf,
+        .length = len};
+
+    rt_spi_transfer_message(RyanW5500SpiDevice, &spiMsg);
+}
+
+/**
+ * @brief SPI 读取多个字节
+ *
+ * @param pbuf
+ * @param len
+ */
+void RyanW5500ReadBurst(uint8_t *pbuf, uint16_t len)
+{
+
+    struct rt_spi_message spiMsg = {
+        .recv_buf = pbuf,
+        .length = len};
+
+    rt_spi_transfer_message(RyanW5500SpiDevice, &spiMsg);
+}
+
+/**
+ * @brief 片选使能
+ *
+ */
+void RyanW5500CsSelect(void)
+{
+    rt_spi_take(RyanW5500SpiDevice);
+}
+
+/**
+ * @brief 片选失能
+ *
+ */
+void RyanW5500CsDeselect(void)
+{
+    rt_spi_release(RyanW5500SpiDevice);
+}
+
+/**
+ * @brief w5500重启函数,只会在w5500初始化时调用
+ *
+ */
+void RyanW5500Reset(void)
+{
+    rt_pin_mode(RyanW5500ResetGpio, PIN_MODE_OUTPUT); // 设置重启引脚电平
+
+    rt_pin_write(RyanW5500ResetGpio, PIN_LOW);
+    rt_thread_mdelay(2);
+
+    rt_pin_write(RyanW5500ResetGpio, PIN_HIGH);
+    rt_thread_mdelay(2);
+}
+
+/**
+ * @brief w5500中断绑定函数,只会在w5500初始化时调用
+ *
+ * @param RyanW5500IRQCallback 中断回调函数
+ */
+void RyanW5500AttachIRQ(void (*RyanW5500IRQCallback)(void *argument))
+{
+    rt_pin_mode(RyanW5500IRQGpio, PIN_MODE_INPUT); // 初始化中断引脚
+    rt_pin_attach_irq(RyanW5500IRQGpio, PIN_IRQ_MODE_FALLING, RyanW5500IRQCallback, NULL);
+    rt_pin_irq_enable(RyanW5500IRQGpio, PIN_IRQ_ENABLE);
+}

+ 26 - 0
platform/RT-Thread/platformW5500Hardware.h

@@ -0,0 +1,26 @@
+
+
+#ifndef __RyanW5500Spi_
+#define __RyanW5500Spi_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#include "RyanApplication.h"
+
+    extern int RyanW5500SpiInit();
+    extern void RyanW5500WriteByte(uint8_t data);
+    extern uint8_t RyanW5500ReadByte(void);
+    extern void RyanW5500WriteBurst(uint8_t *pbuf, uint16_t len);
+    extern void RyanW5500ReadBurst(uint8_t *pbuf, uint16_t len);
+    extern void RyanW5500CriticalEnter(void);
+    extern void RyanW5500CriticalExit(void);
+    extern void RyanW5500CsSelect(void);
+    extern void RyanW5500CsDeselect(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WIZ_SOCKET_H__ */