W5500以太网控制器芯片(六):实现PING服务

#W5500以太网控制芯片相关文章链接#

上一篇:

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的外网设备的功能。
 

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值