W5500之“socket.c”中的相关函数

W5500之"socket.c"中的相关函数如下:

static uint16_t sock_io_mode = 0;

/*sock_io_mode的sn位置1,表示"Socket sn"处于"在非阻塞IO模式",这个Socket通常在忙;Socket正忙于处理该操作。仅在非阻塞IO模式中有效。*/

static uint16_t sock_is_sending = 0;

//sock_is_sending的sn位置1,表示"Socket sn"处于发送状态

static uint16_t sock_remained_size[WIZCHIP_SOCK_NUM] = {0,0,};

//记录"接收包的剩余长度"

//如果一次读不完,就需要读多次,直至sock_remained_size[sn]=0

#define SF_IO_NONBLOCK 0x01

///< Socket nonblock io mode. It used parameter in \ref socket().

1、CHECK_SOCKNUM()宏

#define CHECK_SOCKNUM() \

do{ \

if(sn > WIZCHIP_SOCK_NUM) return SOCKERR_SOCKNUM; \

}while(0);

//如果sn>8,则返回-1,表示sn是"无效的"Socket号码"。

2、CHECK_SOCKMODE(mode)宏

#define CHECK_SOCKMODE(mode) \

do{ \

if((getSn_MR(sn) & 0x0F) != mode) return SOCKERR_SOCKMODE; \

}while(0);

/*读"Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)"的低4位

如果不等于mode,则返回-5,表示"无效的Socket模式"*/

3、CHECK_SOCKINIT()宏

#define CHECK_SOCKINIT() \

do{ \

if((getSn_SR(sn) != SOCK_INIT)) return SOCKERR_SOCKINIT; \

}while(0);

/*读"Socket n状态寄存器(Socket n Status Register,简写Sn_SR)"

如果Sn_SR寄存器的值不是SOCK_INIT,则返回-3,表示"Socket n"没有初始化;

用于"TCP模式"*/

4、CHECK_SOCKDATA()宏

#define CHECK_SOCKDATA() \

do{ \

if(len == 0) return SOCKERR_DATALEN; \

}while(0);

//如果len=0,则返回-14,表示数据长度为0,或是比"Socket n缓冲区的最大值"还大

5、socket()函数

int8_t socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag);

输入参数介绍:

1)、sn:Socket编号,0=<sn<=7;

2)、protocol:Sn_MR寄存器的低4位;

protocol=Sn_MR_TCP,表示"Socket n"使用TCP协议;

protocol=Sn_MR_UDP,表示"Socket n"使用UDP协议;

protocol=Sn_MR_MACRAW,表示"Socket n"使用MACRAW协议;

protocol=Sn_MR_IPRAW,表示"Socket n"使用IPRAW协议;

#define Sn_MR_MACRAW 0x04

/*Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)中的bit3:0(P[3:0])=0100B,表示Socket n使用MACRAW协议。*/

#define Sn_MR_IPRAW 0x03

/*Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)中的bit3:0(P[3:0])=0011B,表示Socket n使用IPRAW协议。*/

#define Sn_MR_UDP 0x02

/*Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)中的bit3:0(P[3:0])=0010B,表示Socket n使用UDP协议*/

#define Sn_MR_TCP 0x01

/*Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)中的bit3:0(P[3:0])=0001B,表示Socket n使用TCP协议*/

3)、port:用来设置"本地的端口";

4)、flag:Sn_MR寄存器的高4位;

#define Sn_MR_MULTI 0x80

/*Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)bit7(MULTI/MFEN)置1,在UDP模式中,使能"组播"。

在将Sn_CR寄存器中的OPEN=1之前,必须先将Sn_DIPR寄存器配置为组播的IP地址"224, 1, 1, 11",再将Sn_DPORT寄存器配置为组播的端口6000,才可以使用组播。

*/

#define Sn_MR_BCASTB 0x40

/*Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)bit6(BCASTB)置1,

在UDP模式中,表示使能阻塞接收"广播数据包";

在MACRAW模式中,表示使能阻塞接收"广播数据包";*/

#define Sn_MR_ND 0x20

/*Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)bit5(ND/MC/MMB),只用于TCP模式;

在TCP模式中,ND/MC/MMB=1后,W5500一旦收到一个数据包,就会毫不延迟地发送ACK包;

在TCP模式中,ND/MC/MMB=0后,W5500会等待"RTR重试定时值寄存器"配置的超时时间后,再发送ACK数据包;

*/

#define Sn_MR_UCASTB 0x10

/*Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)bit4(UCASTB/MIP6B),

在UDP模式中,且MULTI/MFEN=1(使能组播),如果UCASTB/MIP6B=1,它会阻止接收"单播数据包";*/

举例1:ret=socket(0, Sn_MR_TCP, 5000,0);

//令SOCKET编号0工作在TCP模式,并设置TCP端口为5000;

举例2:ret=socket(0, Sn_MR_UDP, 5000, 0x00);

//令SOCKET编号0工作在UDP模式,并设置TCP端口为5000;

举例3:socket(sn, Sn_MR_UDP, 6000, Sn_MR_MULTI);

//将SOCKET通道sn配置为UDP组播模式;

举例4:socket(sn, Sn_MR_MACRAW, 5000, 0x00);

//将SOCKET通道sn配置为MACRAW模式,并设置MACRAW端口为5000;

//函数功能:执行"OPEN命令",初始化并打开"Socket n";

int8_t socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag)

{

CHECK_SOCKNUM();//检查Socket的sn编号是否在合法的范围内

switch(protocol)

{

case Sn_MR_TCP ://"Socket n"使用TCP协议

{

uint32_t taddr;

getSIPR((uint8_t*)&taddr);

//读本地的IP地址寄存器(Source IP Address Register),保存到taddr中

if(taddr == 0) return SOCKERR_SOCKINIT;//返回值为-3

break;

}

case Sn_MR_UDP ://"Socket n"使用UDP协议

case Sn_MR_MACRAW ://"Socket n"使用MACRAW协议

case Sn_MR_IPRAW ://"Socket n"使用IPRAW协议

break;

default :

return SOCKERR_SOCKMODE;//返回值为-5,表示"无效的Socket模式"

}

if((flag & 0x04) != 0)//"Socket n"使用MACRAW协议

return SOCKERR_SOCKFLAG;//返回值为-6

if(flag != 0)

{

switch(protocol)

{

case Sn_MR_TCP://"Socket n"使用TCP协议

if((flag & (SF_TCP_NODELAY|SF_IO_NONBLOCK))==0)

return SOCKERR_SOCKFLAG;

break;

case Sn_MR_UDP://"Socket n"使用UDP协议

if(flag & SF_IGMP_VER2)

{

if((flag & SF_MULTI_ENABLE)==0) return SOCKERR_SOCKFLAG;

}

if(flag & SF_UNI_BLOCK)

{

if((flag & SF_MULTI_ENABLE) == 0) return SOCKERR_SOCKFLAG;

}

break;

default:

break;

}

}

close(sn);////使用"CLOSE命令"关闭"Socket n"

setSn_MR(sn, (protocol | (flag & 0xF0) ));

/*flag为Sn_MR寄存器的高4位;protocol为Sn_MR寄存器的低4位;

将(protocol | (flag & 0xF0) )写入"Socket n模式寄存器(简写Sn_MR)"

protocol=Sn_MR_TCP,表示"Socket n"使用TCP协议

protocol=Sn_MR_UDP,表示"Socket n"使用UDP协议

protocol=Sn_MR_MACRAW,表示"Socket n"使用MACRAW协议

protocol=Sn_MR_IPRAW,表示"Socket n"使用IPRAW协议*/

setSn_PORT(sn,port);//将port写入"Socket n源端口寄存器(简写Sn_PORT)"

setSn_CR(sn,Sn_CR_OPEN);

/*设置"Socket n命令寄存器(简写Sn_CR)",执行open命令,初始化并打开"Socket n"*/

while(getSn_CR(sn)); //等待"Socket n命令寄存器"Sn_CR=0x00

sock_io_mode &= ~(1 <<sn);

sock_io_mode |= ((flag & SF_IO_NONBLOCK) << sn);

//flag最低位为1,即TCP模式

sock_is_sending &= ~(1<<sn);

//sock_is_sending的sn位置0,表示"Socket sn"不处于发送状态

sock_remained_size[sn] = 0;//初始化为0

sock_pack_info[sn] = PACK_COMPLETED;

//这里是初始化Socket,所以令sock_pack_info[sn] = PACK_COMPLETED

//保存的数据还可以是"PACK_FIRST,PACK_REMAINED,PACK_COMPLETED"

while(getSn_SR(sn) == SOCK_CLOSED);

/*等待"Socket n状态寄存器(Socket n Status Register)"Sn_SR!=SOCK_CLOSED

初始化并打开"Socket n"执行后,"Socket n状态寄存器(Socket n Status Register,简写Sn_SR)"的值如下:

在无协议模式中,Sn_SR=0x00,Sn_MR中的P[3:0]用Sn_MR_CLOSE表示;

在TCP模式中,Sn_SR=0x13,用SOCK_INIT表示,Sn_MR中的P[3:0]用Sn_MR_TCP表示;

在UDP模式中,Sn_SR=0x22,用SOCK_UDP表示,Sn_MR中的P[3:0]用Sn_MR_UDP表示;

在MACRAW模式中,Sn_SR=0x42,用SOCK_MACRAW表示,Sn_MR中的P[3:0]用Sn_MR_MACRAW表示;

*/

return (int8_t)sn;//初始化并打开"Socket n"成功,返回"Socket编号";

}

6、close ()函数

//函数功能:使用"CLOSE命令"Sn_CR_CLOSE,关闭"Socket n"

//Socket编号:0=<sn<=7

int8_t close(uint8_t sn)

{

CHECK_SOCKNUM();//检查Socket编号的sn是否在合法的范围内

setSn_CR(sn,Sn_CR_CLOSE);

/*将Sn_CR_CLOSE的值写入"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)";执行CLOSE命令,就会关闭"Socket n",同时,Sn_SR寄存器变成SOCK_CLOSED;*/

while( getSn_CR(sn) );

/*读"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",直到Sn_CR=0,等待"命令"执行完成*/

setSn_IR(sn, 0xFF);

/*根据0xFF,修改"Socket n中断寄存器(Socket n Interrupt Register,简写Sn_IR)"的最低5位值,分别是SEND_OK,TIMEOUT,RECV,DISCON,CON,若写入1,则清除该中断标志位*/

sock_io_mode &= ~(1<<sn);

sock_is_sending &= ~(1<<sn);

//sock_is_sending的sn位置0,表示"Socket sn"不处于发送状态

sock_remained_size[sn] = 0;//关闭Socket,它需要初始化为0

sock_pack_info[sn] = PACK_COMPLETED;

while(getSn_SR(sn) != SOCK_CLOSED);

//读"Socket n状态寄存器(Socket n Status Register,简写Sn_SR)"

//等待"Socket n"关闭。

return SOCK_OK;

}

7、listen()函数

//函数功能:在"TCP服务器模式"中,执行"LISTEN命令",监听SOCKET端口sn

int8_t listen(uint8_t sn)

{

CHECK_SOCKNUM();//如果sn>8,则返回-1,表示sn是"无效的"Socket号码"

CHECK_SOCKMODE(Sn_MR_TCP);

/*读"Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)"的低4位

如果不等于Sn_MR_TCP,则返回-5,表示"无效的Socket模式"*/

CHECK_SOCKINIT();

/*读"Socket n状态寄存器(Socket n Status Register,简写Sn_SR)"

如果Sn_SR寄存器的值不是SOCK_INIT,则返回-3,表示"Socket n"没有初始化;

用于"TCP模式"*/

setSn_CR(sn,Sn_CR_LISTEN);

/*将Sn_CR_LISTEN的值写入"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",执行LISTEN命令,同时,Sn_SR寄存器变成SOCK_LISTEN;*/

while(getSn_CR(sn));

/*读"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",直到Sn_CR=0,等待"命令"执行完成*/

while(getSn_SR(sn) != SOCK_LISTEN)

{

close(sn);//使用"CLOSE命令"关闭"Socket n"

return SOCKERR_SOCKCLOSED;

}

return SOCK_OK;

}

8、connect ()函数

/*函数功能:"TCP客户端模式"执行"CONNECT命令",将SOCKET端口sn连接到服务器IP地址addr和服务器端口port上*/

int8_t connect(uint8_t sn, uint8_t * addr, uint16_t port)

{

uint32_t taddr;

CHECK_SOCKNUM();//如果sn>8,则返回-1,表示sn是"无效的"Socket号码"

CHECK_SOCKMODE(Sn_MR_TCP);

/*读"Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)"的低4位

如果不等于Sn_MR_TCP,则返回-5,表示"无效的Socket模式"*/

CHECK_SOCKINIT();

/*读"Socket n状态寄存器(Socket n Status Register,简写Sn_SR)"

如果Sn_SR寄存器的值不是SOCK_INIT,则返回-3,表示"Socket n"没有初始化;

用于"TCP模式"*/

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;

//检查IP地址是否争取

if(port == 0) return SOCKERR_PORTZERO;

setSn_DIPR(sn,addr);

/*设置"服务器IP地址";将addr[]写入"Socket n的目的IP地址寄存器(Socket n Destination IP Address Register,简写Sn_DIPR)"*/

setSn_DPORT(sn,port);

/*设置"服务器端口";将port写入"Socket n的目的端口寄存器(Socket n Destination Port Register,简写Sn_DPORT)"*/

setSn_CR(sn,Sn_CR_CONNECT);

/*将Sn_CR_CONNECT的值写入"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)";执行CONNECT命令,同时,Sn_SR寄存器变成SOCK_CONNECT*/

while(getSn_CR(sn));

/*读"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",直到Sn_CR=0,等待"命令"执行完成*/

if(sock_io_mode & (1<<sn)) return SOCK_BUSY;

//getSn_SR(sn)读"Socket n状态寄存器(Socket n Status Register,简写Sn_SR)"

while(getSn_SR(sn) != SOCK_ESTABLISHED)//没有建立连接

{

if (getSn_IR(sn) & Sn_IR_TIMEOUT)//连接超时

{

/*读"Socket n中断寄存器(Socket n Interrupt Register,简写Sn_IR)"的最低5位值,分别是SEND_OK,TIMEOUT,RECV,DISCON,CON*/

setSn_IR(sn, Sn_IR_TIMEOUT);

/*根据Sn_IR_TIMEOUT,修改"Socket n中断寄存器(Socket n Interrupt Register,简写Sn_IR)"的最低5位值,置1清除超时标志位*/

return SOCKERR_TIMEOUT;

}

//getSn_SR(sn)读"Socket n状态寄存器(Socket n Status Register,简写Sn_SR)"

if (getSn_SR(sn) == SOCK_CLOSED)//如果"Socket n"关闭

{

return SOCKERR_SOCKCLOSED;

}

}

return SOCK_OK;

}

9、disconnect()函数

//函数功能:TCP模式"使用"DISCON命令",关闭SOCKET端口sn的连接

int8_t disconnect(uint8_t sn)

{

CHECK_SOCKNUM();//如果sn>8,则返回-1,表示sn是"无效的"Socket号码"

CHECK_SOCKMODE(Sn_MR_TCP);

/*读"Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)"的低4位

如果不等于Sn_MR_TCP,则返回-5,表示"无效的Socket模式"*/

setSn_CR(sn,Sn_CR_DISCON);

/*将Sn_CR_DISCON的值写入"Socket n命令寄存器(简写Sn_CR)",执行DISCON命令,同时,Sn_SR寄存器变成SOCK_DISCON;*/

while(getSn_CR(sn));

/*读"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",直到Sn_CR=0,等待"命令"执行完成*/

sock_is_sending &= ~(1<<sn);

//sock_is_sending的sn位置0,表示"Socket sn"不处于发送状态

if(sock_io_mode & (1<<sn)) return SOCK_BUSY;

//getSn_SR(sn)读"Socket n状态寄存器(Socket n Status Register,简写Sn_SR)"

while(getSn_SR(sn) != SOCK_CLOSED)//该"Socket n"没有关闭

{

if(getSn_IR(sn) & Sn_IR_TIMEOUT)//检查是否超时

{

/*读"Socket n中断寄存器(Socket n Interrupt Register,简写Sn_IR)"的最低5位值。分别是SEND_OK,TIMEOUT,RECV,DISCON,CON*/

close(sn);//使用"CLOSE命令"关闭"Socket n"

return SOCKERR_TIMEOUT;

}

}

return SOCK_OK;

}

10、send()函数

//函数功能:"TCP模式"发送数据

/*如果"Socket n的发送缓冲区大小寄存器"的值Sn_TXBUF_SIZE<len,则将"buf为首地址的存储区"的前Sn_TXBUF_SIZE个字节装入"Socket n的发送缓冲区";如果"Socket n的发送缓冲区大小寄存器"的值Sn_TXBUF_SIZE>=len,则将"buf为首地址的存储区"的前len个字节装入"Socket n的发送缓冲区";然后执行"SEND命令",等待命令执行成功;*/

//返回值为"已经发送的数据长度"

int32_t send(uint8_t sn, uint8_t * buf, uint16_t len)

{

uint8_t tmp=0;

uint16_t freesize=0;

CHECK_SOCKNUM();//如果sn>8,则返回-1,表示sn是"无效的"Socket号码"

CHECK_SOCKMODE(Sn_MR_TCP);

/*读"Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)"的低4位

如果不等于Sn_MR_TCP,则返回-5,表示"无效的Socket模式"*/

CHECK_SOCKDATA();

/*如果len=0,则返回-14,表示数据长度为0,或是比"Socket n缓冲区的最大值"还大*/

tmp = getSn_SR(sn);

//读"Socket n状态寄存器(Socket n Status Register,简写Sn_SR)"

if(tmp != SOCK_ESTABLISHED && tmp != SOCK_CLOSE_WAIT)

return SOCKERR_SOCKSTATUS;

//"Socket sn"没有建立连接,也不处于"半关闭状态",则返回SOCKERR_SOCKSTATUS

if( sock_is_sending & (1<<sn) )//sock_is_sending的sn位置1

{

tmp = getSn_IR(sn);

/*读"Socket n中断寄存器(Socket n Interrupt Register,简写Sn_IR)"的最低5位值,分别是SEND_OK,TIMEOUT,RECV,DISCON,CON*/

if(tmp & Sn_IR_SENDOK)//如果"SEND命令"执行完成。

{

setSn_IR(sn, Sn_IR_SENDOK);

/*根据Sn_IR_SENDOK,修改"Socket n中断寄存器(Socket n Interrupt Register,简写Sn_IR)"的最低5位值,分别是SEND_OK,TIMEOUT,RECV,DISCON,CON,若写入1,则清除该中断标志位*/

sock_is_sending &= ~(1<<sn);//sock_is_sending的sn位置0

}

else if(tmp & Sn_IR_TIMEOUT)//超时

{

close(sn);//使用"CLOSE命令"关闭"Socket n"

return SOCKERR_TIMEOUT;

}

else return SOCK_BUSY;

}

freesize = getSn_TxMAX(sn);

/*读"Socket n的发送缓冲区大小寄存器(Sn_TXBUF_SIZE)",返回值为"Sn_TXBUF_SIZE*1024"*/

if (len > freesize) len = freesize;

while(1)

{

freesize = getSn_TX_FSR(sn);

//读"Socket n的发送缓冲区剩余量大小寄存器"

tmp = getSn_SR(sn);

//读"Socket n状态寄存器(Socket n Status Register,简写Sn_SR)"

if ((tmp != SOCK_ESTABLISHED) && (tmp != SOCK_CLOSE_WAIT))

{

close(sn);//使用"CLOSE命令"关闭"Socket n"

return SOCKERR_SOCKSTATUS;

}

if( (sock_io_mode & (1<<sn)) && (len > freesize) ) return SOCK_BUSY;

if(len <= freesize) break;

//如果允许装载数据到"Socket n的发送缓冲区",则退出while循环

}

wiz_send_data(sn, buf, len);

//将"buf为首地址的存储区"的前len个字节装入"Socket n的发送缓冲区";

setSn_CR(sn,Sn_CR_SEND);

/*将Sn_CR_SEND的值写入"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",执行"SEND命令",同时,Sn_SR寄存器变成SOCK_SEND;*/

while(getSn_CR(sn));

/*读"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",直到Sn_CR=0,等待"命令"执行完成*/

sock_is_sending |= (1 << sn);

//sock_is_sending的sn位置1,表示"Socket sn"处于发送状态

return (int32_t)len;

}

11、recv()函数

//函数功能:"TCP模式"接收数据

/*如果"Socket n的接收缓冲区"配置的最大字节数比len大,则从"Socket n的接收缓冲区"读取len个字节保存到buf[]中;如果"Socket n的接收缓冲区"配置的最大字节数比len小,则从"Socket n的接收缓冲区"读取Sn_RXBUF_SIZE个KB保存到buf[]中;执行"RECV命令",直到接收完成*/

//返回值为"已经接收到的数据长度"

int32_t recv(uint8_t sn, uint8_t * buf, uint16_t len)

{

uint8_t tmp = 0;

uint16_t recvsize = 0;

CHECK_SOCKNUM();//如果sn>8,则返回-1,表示sn是"无效的"Socket号码"

CHECK_SOCKMODE(Sn_MR_TCP);

/*读"Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)"的低4位

如果不等于Sn_MR_TCP,则返回-5,表示"无效的Socket模式"*/

CHECK_SOCKDATA();

//如果len=0,则返回-14,表示数据长度为0,或是比"Socket n缓冲区的最大值"还大

recvsize = getSn_RxMAX(sn);

/*读"Socket n的接收缓冲区大小寄存器(Sn_RXBUF_SIZE)",返回值为"Sn_RXBUF_SIZE*1024"*/

if(recvsize < len) len = recvsize;//按照"实际收到的字节数"读取数据

wiz_recv_data(sn, buf, len);

//从"Socket n的接收缓冲区"连续读取len个字节,保存到buf[]中

setSn_CR(sn,Sn_CR_RECV);

/*将Sn_CR_RECV的值写入"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",执行"RECV命令",同时,Sn_SR寄存器变成SOCK_RECV;*/

while(getSn_CR(sn));

/*读"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",直到Sn_CR=0,等待"命令"执行完成*/

return (int32_t)len;

}

12、sendto ()函数

//函数功能:"UDP,MACRAW和IPRAW模式"发送数据

/*如果"Socket n的发送缓冲区大小寄存器"的值Sn_TXBUF_SIZE*1024<len,则将"buf为首地址的存储区"的前Sn_TXBUF_SIZE*1024个字节装入"Socket n的发送缓冲区";

如果"Socket n的发送缓冲区大小寄存器"的值Sn_TXBUF_SIZE*1024>=len,则将"buf为首地址的存储区"的前len个字节装入"Socket n的发送缓冲区";然后执行"SEND命令",等待命令执行成功;*/

//返回值为"已经发送的数据长度"

//addr[]为"对方端的IP地址"

//port[]为"对方端的端口"

int32_t 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();//如果sn>8,则返回-1,表示sn是"无效的"Socket号码"

/*getSn_MR(sn)

读"Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)"

P[3:0]占用"Socket n模式寄存器"的bit3:0,用来指定W5500使用的协议。

P[3:0]=0000B,表示Socket n没有使用任何协议。

P[3:0]=0001B,表示Socket n被配置为TCP协议。

P[3:0]=0010B,表示Socket n被配置为UDP协议。

P[3:0]=0100B,表示Socket n被配置为MACRAW协议。

*/

switch(getSn_MR(sn) & 0x0F)//检查协议是否是"UDP,MACRAW和IPRAW模式"

{

case Sn_MR_UDP:

case Sn_MR_MACRAW:

case Sn_MR_IPRAW:

break;

default:

return SOCKERR_SOCKMODE;

}

CHECK_SOCKDATA();

//如果len=0,则返回-14,表示数据长度为0,或是比"Socket n缓冲区的最大值"还大

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 == 0) && ((getSn_MR(sn)&Sn_MR_MACRAW) != Sn_MR_MACRAW) )

return SOCKERR_IPINVALID;

//如果IP地址为0,且不是"MACRAW模式",则返回SOCKERR_IPINVALID

if((port == 0) && ((getSn_MR(sn)&Sn_MR_MACRAW) != Sn_MR_MACRAW))

return SOCKERR_PORTZERO;

//如果IP地址为0,且不是"MACRAW模式",则返回SOCKERR_PORTZERO

tmp = getSn_SR(sn);

//读"Socket n状态寄存器(Socket n Status Register,简写Sn_SR)"

if((tmp != SOCK_MACRAW) && (tmp != SOCK_UDP) && (tmp != SOCK_IPRAW)) return SOCKERR_SOCKSTATUS;

//如果不是"UDP,MACRAW和IPRAW模式",则返回SOCKERR_SOCKSTATUS

setSn_DIPR(sn,addr);

/*将addr[]中的前4个字节写入"Socket n的目的IP地址寄存器(Socket n Destination IP Address Register,简写Sn_DIPR)"*/

setSn_DPORT(sn,port);

/*将port写入"Socket n的目的端口寄存器(Socket n Destination Port Register,简写Sn_DPORT)"*/

freesize = getSn_TxMAX(sn);

/*读"Socket n的发送缓冲区大小寄存器(Sn_TXBUF_SIZE)",返回值为"Sn_TXBUF_SIZE*1024"*/

if (len > freesize) len = freesize;

//检查是否超过"Socket n的发送缓冲区的最大值",若超过

while(1)

{

freesize = getSn_TX_FSR(sn);

//读"Socket n的发送缓冲区剩余量大小寄存器"

if(getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED;

if( (sock_io_mode & (1<<sn)) && (len > freesize) ) return SOCK_BUSY;

if(len <= freesize) break;

//如果允许装载数据到"Socket n的发送缓冲区",则退出while循环

}

wiz_send_data(sn, buf, len);

//将"buf为首地址的存储区"的前len个字节装入"Socket n的发送缓冲区";

setSn_CR(sn,Sn_CR_SEND);

/*将Sn_CR_SEND的值写入"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",执行"SEND命令",同时,Sn_SR寄存器变成SOCK_SEND;*/

while(getSn_CR(sn));

/*读"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",等待Sn_CR=0,表示"SEND命令"完成*/

while(1)

{

tmp = getSn_IR(sn);

/*读"Socket n中断寄存器(Socket n Interrupt Register,简写Sn_IR)"的最低5位值,分别是SEND_OK,TIMEOUT,RECV,DISCON,CON*/

if(tmp & Sn_IR_SENDOK)//如果发送完成

{

setSn_IR(sn, Sn_IR_SENDOK);

/*根据Sn_IR_SENDOK,修改"Socket n中断寄存器(Socket n Interrupt Register,简写Sn_IR)"的最低5位值,分别是SEND_OK,TIMEOUT,RECV,DISCON,CON,若写入1,则清除该中断标志位*/

break;

}

else if(tmp & Sn_IR_TIMEOUT)//如果超时

{

setSn_IR(sn, Sn_IR_TIMEOUT);

/*根据Sn_IR_TIMEOUT,修改"Socket n中断寄存器(Socket n Interrupt Register,简写Sn_IR)"的最低5位值,置1则将清除相应的中断标志位*/

return SOCKERR_TIMEOUT;

}

}

return (int32_t)len; //返回值为"已经发送的数据长度"

}

13、recvfrom()函数

//函数功能:"UDP,IPRAW和MACRAW协议"接收数据,返回值为"已接收到的数据长度"

//sn是Socket编号

//buf[]保存读到的到数据

//len是打算要这么多个字节

//addr[]保存读到的IP地址

//port[]保存读到的端口

int32_t recvfrom(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port)

{

uint8_t head[8];

uint16_t pack_len=0;

uint8_t mr;

CHECK_SOCKNUM();//如果sn>8,则返回-1,表示sn是"无效的"Socket号码"

mr=getSn_MR(sn);

/*读"Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)"

P[3:0]占用"Socket n模式寄存器"的bit3:0,用来指定W5500使用的协议。

P[3:0]=0000B,表示Socket n没有使用任何协议。

P[3:0]=0001B,表示Socket n被配置为TCP协议。

P[3:0]=0010B,表示Socket n被配置为UDP协议。

P[3:0]=0100B,表示Socket n被配置为MACRAW协议。

*/

switch(mr & 0x0F)//检查是否是"UDP,IPRAW和MACRAW协议"

{

case Sn_MR_UDP:

case Sn_MR_IPRAW:

case Sn_MR_MACRAW:

break;

default:

return SOCKERR_SOCKMODE;//返回值为-5,表示"无效的socket模式"

}

CHECK_SOCKDATA();

//如果len=0,则返回-14,表示数据长度为0,或是比"Socket n缓冲区的最大值"还大

if(sock_remained_size[sn] == 0)//该Socket端口的剩余长度为0

{

while(1)//等待新数据到来

{

pack_len = getSn_RX_RSR(sn);

//读"Socket n的接收缓冲区的接收量大小寄存器",直到W5500接收完成

if(getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED;

/*读"Socket n状态寄存器(Socket n Status Register,简写Sn_SR)",如果Sn_SR=SOCK_CLOSED,返回-4,表示"该Socket端口意外关闭",接收数据长度无效*/

if( (sock_io_mode & (1<<sn)) && (pack_len == 0) ) return SOCK_BUSY;

if(pack_len != 0) break;

//读到"Socket n的接收缓冲区的接收量大小寄存器"的数据

}

}

switch (mr & 0x07) //根据"UDP,IPRAW和MACRAW协议"处理

{

case Sn_MR_UDP ://执行UDP接收

if(sock_remained_size[sn] == 0)//该Socket端口的剩余长度为0

{

wiz_recv_data(sn, head, 8);

//从"Socket n的接收缓冲区"连续读取8个字节,保存到head[]中

setSn_CR(sn,Sn_CR_RECV);

/*将Sn_CR_RECV的值写入"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",执行"RECV命令"*/

while(getSn_CR(sn));

/*读"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",等待Sn_CR=0,表示"RECV命令"完成*/

addr[0] = head[0];//保存"对方端"的IP地址

addr[1] = head[1];//保存"对方端"的IP地址

addr[2] = head[2];//保存"对方端"的IP地址

addr[3] = head[3];//保存"对方端"的IP地址

*port = head[4];//保存"对方端"的端口

*port = (*port << 8) + head[5];//保存"对方端"的端口

sock_remained_size[sn] = head[6];//保存接收包长度的高8位

sock_remained_size[sn] = (sock_remained_size[sn] << 8) + head[7];

//保存接收包长度的低8位

sock_pack_info[sn] = PACK_FIRST;//记录第1包

}

if(len < sock_remained_size[sn]) pack_len = len;

else pack_len = sock_remained_size[sn];

len = pack_len;//保存允许的剩余长度

wiz_recv_data(sn, buf, pack_len);

//从"Socket n的接收缓冲区"连续读取pack_len个字节,保存到buf[]中

break;

case Sn_MR_MACRAW :

if(sock_remained_size[sn] == 0)

{

wiz_recv_data(sn, head, 2);

//从"Socket n的接收缓冲区"连续读取2个字节,保存到head[]中

setSn_CR(sn,Sn_CR_RECV);

/*将Sn_CR_RECV的值写入"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",执行"RECV命令"*/

while(getSn_CR(sn));

/*读"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",等待Sn_CR=0,表示"RECV命令"完成*/

//读"对方端"的IP地址,端口号码和包长度

sock_remained_size[sn] = head[0];

sock_remained_size[sn] = (sock_remained_size[sn] <<8) + head[1] -2;

if(sock_remained_size[sn] > 1514)

{

close(sn);//使用"CLOSE命令"关闭"Socket n"

return SOCKFATAL_PACKLEN;

}

sock_pack_info[sn] = PACK_FIRST; //记录第1包

}

if(len < sock_remained_size[sn]) pack_len = len;

else pack_len = sock_remained_size[sn];

wiz_recv_data(sn,buf,pack_len);

//从"Socket n的接收缓冲区"连续读取pack_len个字节,保存到buf[]中

break;

case Sn_MR_IPRAW:

if(sock_remained_size[sn] == 0)

{

wiz_recv_data(sn, head, 6);

//从"Socket n的接收缓冲区"连续读取6个字节,保存到head[]中

setSn_CR(sn,Sn_CR_RECV);

/*将Sn_CR_RECV的值写入"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",执行"RECV命令"*/

while(getSn_CR(sn));

/*读"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",等待Sn_CR=0,表示"RECV命令"完成*/

addr[0] = head[0];//保存对方端的IP地址

addr[1] = head[1];

addr[2] = head[2];

addr[3] = head[3];

sock_remained_size[sn] = head[4];

sock_remained_size[sn] = (sock_remained_size[sn] << 8) + head[5];

sock_pack_info[sn] = PACK_FIRST; //记录第1包

}

if(len < sock_remained_size[sn]) pack_len = len;

else pack_len = sock_remained_size[sn];

wiz_recv_data(sn, buf, pack_len);

//从"Socket n的接收缓冲区"连续读取pack_len个字节,保存到buf[]中

break;

default:

wiz_recv_ignore(sn, pack_len);

/*修改"Socket n的接收缓冲区的读指针寄存器(Socket n RX Read Pointer Register,简写Sn_RX_RD)",使"Socket n的接收缓冲区的读指针"增加pack_len。*/

sock_remained_size[sn] = pack_len;

break;

}

setSn_CR(sn,Sn_CR_RECV);

/*将Sn_CR_RECV的值写入"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",执行"RECV命令"*/

while(getSn_CR(sn)) ;

/*读"Socket n命令寄存器(Socket n Command Register,简写Sn_CR)",等待Sn_CR=0,表示"RECV命令"完成*/

sock_remained_size[sn] -= pack_len;

if(sock_remained_size[sn] != 0)

{

sock_pack_info[sn] |= PACK_REMAINED;//记录没有读完

}

else sock_pack_info[sn] = PACK_COMPLETED;//记录读完所有数据

return (int32_t)pack_len;//返回值为"已接收到的数据长度"

}

14、setsockopt()函数

int8_t setsockopt(uint8_t sn, sockopt_type sotype, void* arg);

//sn是Socket编号

//arg用来指向待写入的数据;

//sotype=SO_TTL,将"*(uint8_t*)arg"写入"Socket n的TTL值寄存器(Socket n IP TTL Register,简写Sn_TTL)";

//sotype=SO_TOS,将"*(uint8_t*)arg"写入"Socket n的IP报文转发优先级寄存器(Socket n IP TOS Register,简写Sn_TOS)";

//sotype=SO_MSS,将"*(uint16_t*)arg"的双字节值写入"Socket n的最大分段大小寄存器(Socket n Maximum Segment Size Register,简写Sn_MSSR)";

//sotype=SO_DESTIP,将"(uint8_t*)arg"为首地址缓存的前4个字节写入"Socket n的目的IP地址寄存器(Socket n Destination IP Address Register,简写Sn_DIPR)";

//sotype=SO_DESTPORT,将"*(uint16_t*)arg"写入"Socket n的目的端口寄存器(Socket n Destination Port Register,简写Sn_DPORT)";

//sotype=SO_KEEPALIVESEND,"TCP模式"中,如果Sn_KPALVTR > 0,W5500会在"一定时间周期"内自动传输"KA数据包"以检查TCP的连接状态(自动在线验证)。

//sotype=SO_KEEPALIVESEND,"TCP模式"中,如果Sn_KPALVTR = 0,通过SEND_KEEP命令发送"1字节在线心跳包"来检查连接状态。

//sotype=SO_KEEPALIVEAUTO,将"*(uint8_t*)arg"写入"保活定时器寄存器(Keep alive timer Register,简写Sn_KPALVTR)",配置为"自动在线验证";

15、getsockopt ()函数

int8_t getsockopt(uint8_t sn, sockopt_type sotype, void* arg);

//sn是Socket编号

//arg用来指向读到的数据;

//sotype=SO_FLAG,用来读"Socket n模式寄存器(Socket n Mode Register,简写Sn_MR)";

//sotype=SO_TTL,用来读"Socket n的TTL值寄存器(Socket n IP TTL Register,简写Sn_TTL)";

//sotype=SO_TOS,用来读"Socket n的IP报文转发优先级寄存器(Socket n IP TOS Register,简写Sn_TOS)";

//sotype=SO_MSS,用来读"Socket n的最大分段大小寄存器(Socket n Maximum Segment Size Register,简写Sn_MSSR)",返回双字节值;

//sotype=SO_DESTIP,从"Socket n的目的IP地址寄存器(Socket n Destination IP Address Register)"读取4个字节;

//sotype=SO_DESTPORT,从"Socket n的目的端口寄存器(Socket n Destination Port Register,简写Sn_DPORT)"读取双字节数值;

//sotype=SO_KEEPALIVEAUTO,在"TCP"模式中,读"保活定时器寄存器(Keep alive timer Register,简写Sn_KPALVTR)";

//sotype=SO_SENDBUF,读"Socket n的发送缓冲区剩余量大小寄存器";

//sotype=SO_RECVBUF,读"Socket n的接收缓冲区的接收量大小寄存器";

//sotype=SO_STATUS,读"Socket n状态寄存器(Socket n Status Register,简写Sn_SR)"

//sotype=SO_REMAINSIZE,读"接收包的剩余长度";

//sotype=SO_PACKINFO,读"接收包的信息";