lwip--让你的设备拥有PING别的设备的功能

/**/

点击查看代码
#include "CompletePing.h"

/** ping identifier - must fit on a u16_t */
#ifndef PING_ID
#define PING_ID        0xAFAF// Ping包的唯一ID
#endif

#define PING_DATA_SIZE 32          // Ping数据大小

static u32_t ping_time = 0;
static uint8_t Ping_index;

static struct raw_pcb *ping_pcb = NULL;

// 互斥锁保护缓冲区,避免并发访问(可选,视具体环境是否需要)
sys_mutex_t ip_mutex;

//
void update_ip_buffer(char dev_index,const char *new_ip) {
    // 进入临界区,保护缓冲区
    sys_mutex_lock(&ip_mutex);
    
    // 清空缓冲区,并复制新的IP地址
    memset(PDU_Info_Data.IP_Addr[dev_index].IP_Addr_buf, 0, 40);
    sprintf(PDU_Info_Data.IP_Addr[dev_index].IP_Addr_buf,"%s",new_ip);
    
    PDU_Info_Data.IP_Addr[dev_index].ip_updated = true;  // 标记为已更新
    sys_mutex_unlock(&ip_mutex);  // 释放互斥锁
}
//
static u8_t ping_recv_callback(void *arg, struct raw_pcb *pcb, struct pbuf *p,const ip_addr_t *addr)
{
    struct ip_hdr *iphdr;
    u16_t iphdr_hlen;
	struct icmp_echo_hdr *iecho;
    u16_t echo_type;
    u16_t echo_id;
	LWIP_UNUSED_ARG(arg);
	LWIP_UNUSED_ARG(pcb);
	LWIP_UNUSED_ARG(addr);
	LWIP_ASSERT("p != NULL", p != NULL);
    
    // 获取IP头部的长度,IPv4最常见的头部长度是20字节
    iphdr = (struct ip_hdr *)p->payload;
    iphdr_hlen = IPH_HL(iphdr) * 4;  // 头部长度是以4字节为单位的
    // 跳过IP头部,获取ICMP头部
    iecho = (struct icmp_echo_hdr *)((u8_t*)p->payload + iphdr_hlen);
    
    #if 1
    echo_type = __REV16(ICMPH_TYPE(iecho));
    echo_id = __REV16(iecho->id);
    #else
    printf("iecho->type = [%x]\r\n",echo_type);
    printf("iecho->id = [%x]\r\n",echo_id);
    printf("\r\niecho->type2 = [%x]\r\n",iecho->type);
    printf("iecho->chksum2 = [%x]\r\n",iecho->chksum);
    printf("iecho->code2 = [%x]\r\n",iecho->code);
    printf("iecho->id2 = [%x]\r\n",iecho->id);
    printf("iecho->seqno2 = [%x]\r\n",iecho->seqno);
    #endif
    
	if ((echo_type == ICMP_ER) && echo_id == PING_ID) {
		printf("ping: recv timeout %"U32_F" ms\n", (PDU_Info_Data.PingTimeOutms[Ping_index] = (sys_now()-ping_time)));
		xSemaphoreGiveFromISR(xSemaphorePING, NULL);// 释放二值信号量,通知设备PING响应成功
        pbuf_free(p);
        return 1; // 成功接收ping回复
	}
	return 0;
}
/**/
static void ping_send(struct raw_pcb *pcb, const ip_addr_t *addr) {
    struct pbuf *p;
    struct icmp_echo_hdr *iecho;
    size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
    
    p = pbuf_alloc(PBUF_IP, ping_size, PBUF_RAM);
    if (p != NULL) {
        iecho = (struct icmp_echo_hdr *)p->payload;
        ICMPH_TYPE_SET(iecho, ICMP_ECHO);
        ICMPH_CODE_SET(iecho, 0);
        iecho->chksum = 0;
        iecho->id = PING_ID;
        iecho->seqno = htons(0x0100);
        
        iecho->chksum = inet_chksum(iecho, ping_size);
        raw_sendto(pcb, p, addr);
        pbuf_free(p);
    }
}
//
#if(1)
/*ping函数用于ping其他设备*/
static void Ping_test(char *pIPaddr)
{
    static ip_addr_t target_ip;
	unsigned int inaddr=0l;
	struct hostent *host;
	char *ip_str = NULL;
	u8 Ping_remote_ip[4] = {0};
	
	/*判断是主机名还是ip地址*/
	inaddr=inet_addr(pIPaddr);
    if(inaddr == INADDR_NONE)
    {
		printf("用户ping输入的类型为域名%s\r\n",pIPaddr);
		host=gethostbyname(pIPaddr);
		if(host != NULL) /**/
		{
			 ip_str = inet_ntoa(*((struct in_addr *)host->h_addr_list[0]));// 只取第一个 IP 地址
		}
	}
	else
	{
		ip_str = pIPaddr;
	}
	sscanf(ip_str, "%hhu.%hhu.%hhu.%hhu", &Ping_remote_ip[0], &Ping_remote_ip[1], &Ping_remote_ip[2], &Ping_remote_ip[3]);	
	printf("用户ping的ip地址为%hhu.%hhu.%hhu.%hhu ",Ping_remote_ip[0], Ping_remote_ip[1], Ping_remote_ip[2], Ping_remote_ip[3]);
	IP4_ADDR(&target_ip, Ping_remote_ip[0],Ping_remote_ip[1],Ping_remote_ip[2],Ping_remote_ip[3]);//MCU 要ping的设备IP
	
    if (1)
    {
        ping_send(ping_pcb, &target_ip);
        
		ping_time = sys_now();
        
		if(xSemaphoreTake(xSemaphorePING,1000))//等待1000ms获取信号量
		{
			printf("PING success!\r\n");
		}
		else
		{
			PDU_Info_Data.PingTimeOutms[Ping_index] = 5000;
			printf("PING timeout is more than 1000ms\r\n");
			#if (0)
			if(PDU_Info_Data.timeout_action[Ping_index] == 0)//重启
			{
				vTaskDelay((PDU_Info_Data.OpenDalay[Ping_index]));	//断开延时
				Set_Data_Bit(&(PDU_Info_Data.ralay_status),Ping_index,0);//设置插座状态
				Set_Relays_Status(PDU_Info_Data.ralay_status);//发送状态断开对应插座
				vTaskDelay((PDU_Info_Data.CloseDalay[Ping_index]));	//断开延时
				Set_Data_Bit(&(PDU_Info_Data.ralay_status),Ping_index,1);//设置插座状态
				Set_Relays_Status(PDU_Info_Data.ralay_status);//闭合对应插座
			}
			else if(PDU_Info_Data.timeout_action[Ping_index] == 1)//关闭插座
			{
				vTaskDelay((PDU_Info_Data.OpenDalay[Ping_index]));	//断开延时
				Set_Data_Bit(&(PDU_Info_Data.ralay_status),Ping_index,0);//设置插座状态
				Set_Relays_Status(PDU_Info_Data.ralay_status);//发送状态断开对应插座
			}
			else//重置超时动作
			{
				PDU_Info_Data.timeout_action[Ping_index] = 0;
			}
			#endif
		}
    }
	
}
#endif
//
static void ping_device_thread(void *pvParameters)
{
    // 创建raw PCB
    ping_pcb = raw_new(IP_PROTO_ICMP);
    if (ping_pcb != NULL) {
        raw_recv(ping_pcb, ping_recv_callback, NULL);  // 设置接收回调
    }
    
    #ifdef PING_DEBUG
    PDU_Info_Data.IP_Addr[0].ip_updated = true;
    sprintf(PDU_Info_Data.IP_Addr[0].IP_Addr_buf,"%s","192.168.1.140");
    #endif
    
    for(;;)
    {
        for(int i=0;i<6;i++)
        {
            sys_mutex_lock(&ip_mutex);  // 进入临界区,保护缓冲区PDU_Info_Data.IP_Addr[i]
            if (PDU_Info_Data.IP_Addr[i].ip_updated) // 如果IP已更新
            {  
//                PDU_Info_Data.IP_Addr[0].ip_updated = false;
                Ping_test(PDU_Info_Data.IP_Addr[i].IP_Addr_buf);
            }
            sys_mutex_unlock(&ip_mutex);  // 释放互斥锁
            vTaskDelay(100);  // 每隔1秒检查一次缓冲区
        }
        
    }
}
//
void ping_thread_create(void)
{
    // 初始化互斥锁
    sys_mutex_new(&ip_mutex);
    
    xTaskCreate(ping_device_thread, "ping_device_thread", 512, NULL,9, NULL);//
}

posted @ 2024-09-26 16:13  BUG_KING  阅读(156)  评论(0编辑  收藏  举报