上一篇:
W5500以太网控制器芯片(五):实现FTP客户端
PING使用的是ICMP的协议,使用时最好先了解一下。
下面实现一下使用w5500来ping外网的指定ip设备的流程。注意需要包含官方ioLibrary库的w5500和socket文件,具体可以参考本系列前面的文章,当然也可以自己实现上面调用的函数。
头文件:
#ifndef _PING_H_
#define _PING_H_
#include "w5500.h"
#include "w5500_socket.h"
#define PING_BUF_LEN 32
#define PING_REQUEST 8
#define PING_REPLY 0
#define CODE_ZERO 0
#define SOCKET_ERROR 1
#define TIMEOUT_ERROR 2
#define SUCCESS 3
#define REPLY_ERROR 4
typedef struct pingmsg
{
uint8_t Type; // 0 - Ping Reply, 8 - Ping Request
uint8_t Code; // Always 0
uint16_t CheckSum; // Check sum
uint16_t ID; // Identification
uint16_t SeqNum; // Sequence Number
int8_t Data[PING_BUF_LEN];// Ping Data : 1452 = IP RAW MTU - sizeof(Type+Code+CheckSum+ID+SeqNum)
} PINGMSGR;
uint8_t ping_count(uint8_t sn, uint16_t pCount, uint8_t *addr);
uint8_t ping_request(uint8_t s, uint8_t *addr);
uint8_t ping_reply(uint8_t s, uint8_t *addr, uint16_t rlen);
void Ethernet_ping_service_deal(uint8_t sn);
#endif
C文件:
1、相关宏、变量定义
#define Sn_PROTO(ch) (0x001408 + (ch << 5))
#define PING_BIND_PORT 3000
PINGMSGR PingRequest = {0};
PINGMSGR PingReply = {0};
static uint16_t ping_RandomID = 0x1234;
static uint16_t ping_RandomSeqNum = 0x4321;
uint8_t ping_reply_received = 0;
uint8_t ping_req = 0;
uint8_t ping_rep = 0;
uint8_t ping_cnt = 0;
uint8_t ping_rep_buf[150] = {0};
//ping状态机
#define PING_STA_FREE 0
#define PING_STA_OPEN 1
#define PING_STA_SEND 2
#define PING_STA_WAIT 3
#define PING_STA_CLOSE 4
uint8_t ping_sta = PING_STA_FREE;
//当前ping的设备的序号
u8 ping_device_serial = 0;
//PING目标
u8 ping_ip_dest[4] = {10, 1, 1, 197};
2、实现PING服务,主要是定时开启ping服务,ping完指定设备IP列表的设备完成后,关闭通道,实际请根据自己的需求做一些改动
//PING服务处理,约50ms执行一次
void Ethernet_ping_service_deal(uint8_t sn)
{
static u16 ping_cycle = 0;
uint16_t rlen;
u8 i, res = 0;
//当前通道状态
uint8_t sn_sr = 0;
switch (ping_sta)
{
case PING_STA_FREE: //空闲状态
{
ping_cycle++;
if (ping_cycle > 50 * 20)
{
ping_cycle = 0;
ping_sta = PING_STA_OPEN;
}
break;
}
case PING_STA_OPEN: //开启通道
{
sn_sr = getSn_SR(sn);
if (sn_sr == SOCK_CLOSED)
{
w5500_close(sn);
/* Create Socket */
IINCHIP_WRITE(Sn_PROTO(sn), IPPROTO_ICMP); /*设置ICMP 协议*/
if (w5500_socket(sn, Sn_MR_IPRAW, PING_BIND_PORT, 0) != 0) /*判断ip raw模式socket是否开启*/
{
}
}
else if (sn_sr == SOCK_IPRAW)
{
ol_print(DEBUG_CHN, 0, "Ping socket open\n");
ping_device_serial = 0;
ping_req = 0;
ping_rep = 0;
ping_sta = PING_STA_SEND;
}
break;
}
case PING_STA_SEND: //发送数据
{
//查询完1轮,断开连接
if (ping_device_serial > 15)
{
ping_sta = PING_STA_CLOSE;
break;
}
//判断是否查询完毕
for (i = ping_device_serial; i < 16; i++)
{
if (System_Para.ethernet_ping_ip[i][0] != 0)
{
ping_device_serial = i;
if (ping_req == 0)
{
ping_rep = 0;
memcpy(ping_ip_dest, System_Para.ethernet_ping_ip[i], 4);
ol_print(DEBUG_CHN, 0, "Ping:%d.%d.%d.%d\r\n", (ping_ip_dest[0]), (ping_ip_dest[1]), (ping_ip_dest[2]), (ping_ip_dest[3]));
}
ping_req++;
ping_request(sn, ping_ip_dest); /*发送Ping请求*/
ping_sta = PING_STA_WAIT;
ping_cnt = 0;
break;
}
}
//查询完毕
if(i == 16)
{
ping_sta = PING_STA_CLOSE;
break;
}
}
case PING_STA_WAIT: //等待结果
{
if ((rlen = getSn_RX_RSR(sn)) > 0)
{
rlen = ping_reply(sn, ping_ip_dest, rlen); /*获取回复信息*/
ping_rep++;
if (ping_reply_received)
{
ol_print(DEBUG_CHN, 0, "rep%d t=%d,len=%d\n",ping_req,ping_cnt, rlen);
ping_sta = PING_STA_SEND;
if(ping_req == 4)
{
ping_req = 5;
}
}
}
if ((ping_cnt > 50)) //超过4次,结束查询
{
ol_print(DEBUG_CHN, 0, "rep time out\r\n\r\n");
ping_cnt = 0;
ping_sta = PING_STA_SEND;
if(ping_req == 4)
{
ping_req = 5;
}
}
else
{
ping_cnt++;
}
//ping完4次后,ping下一台设备
if (ping_req == 5)
{
ol_print(DEBUG_CHN, 0, "ping %d.%d.%d.%d, s=4, r=%d, l=%d\n",
ping_ip_dest[0], ping_ip_dest[1], ping_ip_dest[2], ping_ip_dest[3], ping_rep, 4 - ping_rep);
if (ping_rep == 0)
{
System_Sta.ping_list_sta &= ~(0x0001 << ping_device_serial);
}
else
{
System_Sta.ping_list_sta |= (0x0001 << ping_device_serial);
}
ping_rep = 0;
ping_req = 0;
ping_device_serial++;
}
break;
}
case PING_STA_CLOSE: //关闭通道
{
ol_print(DEBUG_CHN, 0, "Ping socket close\n");
w5500_close(sn);
ping_sta = PING_STA_FREE;
break;
}
}
}
3、ping指定次数的设备IP函数实现
/**
*@brief 设定次数ping外网IP函数
*@param sn- socket number
*@param addr- 外网IP地址
*@param pCount- ping的次数
*@return ping成功次数
*/
u8 ping_count(uint8_t sn, uint16_t pCount, uint8_t *addr)
{
uint16_t rlen, cnt, i;
ping_reply_received = 0;
ping_req = 0;
ping_rep = 0;
ol_print(DEBUG_CHN, 0, "Ping:%d.%d.%d.%d\r\n", (addr[0]), (addr[1]), (addr[2]), (addr[3]));
for (i = 0; i < pCount + 1; i++) /*循环ping pCount次*/
{
switch (getSn_SR(sn)) /*获取socket状态*/
{
case SOCK_CLOSED: /*socket关闭状态*/
{
w5500_close(sn);
/* Create Socket */
IINCHIP_WRITE(Sn_PROTO(sn), IPPROTO_ICMP); /*设置ICMP 协议*/
if (w5500_socket(sn, Sn_MR_IPRAW, PING_BIND_PORT, 0) != 0) /*判断ip raw模式socket是否开启*/
{
}
/* Check socket register */
while (getSn_SR(sn) != SOCK_IPRAW)
{
osiThreadSleep(50);
};
break;
}
case SOCK_IPRAW: /*ip raw模式*/
{
cnt = 0;
ping_request(sn, addr); /*发送Ping请求*/
ping_req++;
while (1)
{
if ((rlen = getSn_RX_RSR(sn)) > 0)
{
rlen = ping_reply(sn, addr, rlen); /*获取回复信息*/
ping_rep++;
if (ping_reply_received)
{
ol_print(DEBUG_CHN, 0, "rep t=%d,len=%d\n", cnt, rlen);
break;
}
}
if ((cnt > 50))
{
ol_print(DEBUG_CHN, 0, "rep time out\r\n\r\n");
cnt = 0;
break;
}
else
{
cnt++;
osiThreadSleep(10);
}
}
break;
}
default:
break;
}
if (ping_req >= pCount)
{
w5500_close(sn);
}
}
return ping_rep;
}
4、ping请求函数
/**
*@brief ping请求函数
*@param sn- socket number
*@param addr- P地址
*@return 无
*/
uint8_t ping_request(uint8_t sn, uint8_t *addr)
{
uint8_t *buffer;
uint16_t i, temp_len = 0;
ping_reply_received = 0; /*ping 回复初始化标志位*/
PingRequest.Type = PING_REQUEST; /*Ping-Request*/
PingRequest.Code = CODE_ZERO; /*总是 '0'*/
PingRequest.ID = htons(ping_RandomID++); /*设置ping响应ID为随机的整型变量*/
PingRequest.SeqNum = htons(ping_RandomSeqNum++); /*设置ping响应的序列号为随机整形变量*/
for (i = 0; i < PING_BUF_LEN; i++)
{
PingRequest.Data[i] = (i) % 8; /*ping相应的数在'0'~'8‘*/
}
PingRequest.CheckSum = 0;
/* 计算响应次数*/
PingRequest.CheckSum = htons(checksum((uint8_t *)&PingRequest, sizeof(PingRequest)));
/*发送ping响应到目的方 */
if (w5500_sendto(sn, (uint8_t *)&PingRequest, sizeof(PingRequest), addr, PING_BIND_PORT) == 0)
{
ol_print(DEBUG_CHN, 0, "Fail to send ping-reply packet\r\n");
}
else
{
// ol_print(DEBUG_CHN, 0, "ping send\n");
}
return 0;
}
5、解析ping回复
/**
*@brief 解析Ping回复
*@param sn- socket number
*@param addr- Ping地址
*@return 无
*/
uint8_t ping_reply(uint8_t sn, uint8_t *addr, uint16_t rlen)
{
uint16_t tmp_checksum;
uint16_t len;
uint16_t i;
uint16_t port = PING_BIND_PORT;
PINGMSGR PingReply;
memset(ping_rep_buf, 0, sizeof(ping_rep_buf));
len = w5500_recvfrom(sn, ping_rep_buf, rlen, addr, &port); /*从目的端接收数据*/
if (ping_rep_buf[0] == PING_REPLY)
{
PingReply.Type = ping_rep_buf[0];
PingReply.Code = ping_rep_buf[1];
PingReply.CheckSum = (ping_rep_buf[3] << 8) + ping_rep_buf[2];
PingReply.ID = (ping_rep_buf[5] << 8) + ping_rep_buf[4];
PingReply.SeqNum = (ping_rep_buf[7] << 8) + ping_rep_buf[6];
for (i = 0; i < len - 8; i++)
{
PingReply.Data[i] = ping_rep_buf[8 + i];
}
tmp_checksum = ~checksum(ping_rep_buf, len); /*检查ping回复的次数*/
if (tmp_checksum != 0xffff)
{
ol_print(DEBUG_CHN, 0, "tmp_checksum = %x\r\n", tmp_checksum);
}
else
{
ol_print(DEBUG_CHN, 0, "Reply from %3d.%3d.%3d.%3d ID=%x Byte=%d\r\n\r\n", (addr[0]), (addr[1]), (addr[2]), (addr[3]), htons(PingReply.ID), (rlen + 6));
ping_reply_received = 1; /*当退出ping回复循环时,设置ping回复标志为1*/
}
}
else if (ping_rep_buf[0] == PING_REQUEST)
{
PingReply.Code = ping_rep_buf[1];
PingReply.Type = ping_rep_buf[2];
PingReply.CheckSum = (ping_rep_buf[3] << 8) + ping_rep_buf[2];
PingReply.ID = (ping_rep_buf[5] << 8) + ping_rep_buf[4];
PingReply.SeqNum = (ping_rep_buf[7] << 8) + ping_rep_buf[6];
for (i = 0; i < len - 8; i++)
{
PingReply.Data[i] = ping_rep_buf[8 + i];
}
tmp_checksum = PingReply.CheckSum; /*检查ping回复次数*/
PingReply.CheckSum = 0;
if (tmp_checksum != PingReply.CheckSum)
{
ol_print(DEBUG_CHN, 0, " \n CheckSum is in correct %x shold be %x \n", (tmp_checksum), htons(PingReply.CheckSum));
}
else
{
}
ol_print(DEBUG_CHN, 0, " Request from %d.%d.%d.%d ID:%x SeqNum:%x :data size %d bytes\r\n",
(addr[0]), (addr[1]), (addr[2]), (addr[3]), (PingReply.ID), (PingReply.SeqNum), (rlen + 6));
ping_reply_received = 1; /* 当退出ping回复循环时,设置ping回复标志为1 */
}
else
{
ol_print(DEBUG_CHN, 0, " Unkonwn msg. \n");
}
return 0;
}
以上内容就实现了ping指定IP的外网设备的功能。