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,读"接收包的信息";