/**/
点击查看代码
#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);//
}