硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1358|回复: 9
收起左侧

[ThreadX全家桶] 请教下,使用 netx ,开启 dhcp, 插拔测试只能 <=2 次能够获取到 ip 地址 ?

[复制链接]

610

主题

3060

回帖

4910

积分

至尊会员

积分
4910
发表于 2022-5-31 10:55:47 | 显示全部楼层 |阅读模式
请教下,使用 netx ,开启 dhcp, 插拔测试只能 <=2 次能够获取到 ip 地址 ?
第三次貌似 dhcp 就不工作了 ??

0033.png

最后一次就 在 获取 ip 地址后就没有反应了,但是程序是没有死机或者卡死,想问一下,出现这样的情况,问题一般是出现在哪里 ???

每插拔一次就会删除一次相关任务,信号量 等,

插拔一次,就会删除一次
void DHCP_delete_user(void)
{
        UINT status;
        if(dhcp_client.nx_dhcp_id)
        {
                tx_thread_sleep(10);
                status =        nx_dhcp_stop(&dhcp_client);
                if(status == TX_SUCCESS)  {
                        NX_Debug("dhcp nx_dhcp_stop SUCCESS \r\n");
                }
               
                tx_thread_sleep(10);
                status =        nx_dhcp_delete(&dhcp_client);
                if(status == TX_SUCCESS)  {
                        dhcp_client.nx_dhcp_id = 0;
                        NX_Debug("dhcp nx_dhcp_delete SUCCESS \r\n");
                }
               
                if(dhcp_semaphore.tx_semaphore_id != 0) {
                        status = tx_semaphore_delete(&dhcp_semaphore);
                        if(status == TX_SUCCESS)  {
                                dhcp_semaphore.tx_semaphore_id = 0;
                                NX_Debug("dhcp tx_semaphore_delete SUCCESS \r\n");
                        }                       
                }
               
                ip_address = 0;
                tx_thread_sleep(10);
        }




/*
************************************************************************************************
删除任务及相应的控制块
************************************************************************************************
*/
void tcp_thread_delete_user(void)
{
        UINT       status;
        if(tcp_socket.nx_tcp_socket_id != 0)
        {
                tcp_thread_connect_status_clr();  // 连接成功标志清 0
               
                /* Disconnect the server socket. 断开服务器连接 */
                status =  nx_tcp_socket_disconnect(&tcp_socket, NX_WAIT_FOREVER);  // NX_IP_PERIODIC_RATE
                if (status)
                {
                        NX_Debug("tcp_s socket_disconnect error\r\n");
                }

                /* Unaccept the server socket. 解除服务器套接字 */
                status =  nx_tcp_server_socket_unaccept(&tcp_socket);
                if (status)
                {
                        NX_Debug("tcp_s socket_unaccept error\r\n");
                }

                status =  nx_tcp_server_socket_unlisten(&nx_ip, NX_CLIENT_PORT);
                if (status)
                {
                        NX_Debug("tcp_s socket_unlisten error\r\n");
                }
               
                status =  nx_tcp_socket_delete(&tcp_socket);
                if (status)
                {
                        NX_Debug("tcp_s socket_delete error\r\n");
                }
        }
       
        nx_packet_pool_delete(&nx_packet_pool);
        nx_ip_delete(&nx_ip);
       
        if(tcp_thread.tx_thread_id != 0)
        {
                tx_thread_terminate(&tcp_thread);  // 先终止自身任务
                status =  tx_thread_delete(&tcp_thread);
                if(status == TX_SUCCESS)
                {
                        NX_Debug("tcp thread delete SUCCESS\r\n");
                }
                else
                {
                        NX_Debug("tcp thread delete ERROR = 0x%X\r\n", status);
                }
        }

        NETX_Memory(1);   // 释放内存
        netx_init_flag = 0;  //重新赋值为 0,为下次工作做准备
}


// 状态检测及处理任务
void ethernetif_set_link(ULONG thread_input)
{
        NX_PARAMETER_NOT_USED(thread_input);

        int32_t          PHYLinkState;
        int32_t    EthLinkStatus = 0;

        while(LAN8742_hardware_init_status_get() != 1) {   // 等待 LAN8742 硬件初始化完成
       
                tx_thread_sleep(1000);
        }
               
        while(g_ucEthLinkStatus != 2) {   // 等待 lan8742 初始化完成
                tx_thread_sleep(1000);
        }
       
        while(1)
        {
                        /* Get link state */
                        PHYLinkState = nx_eth_phy_get_link_state();
                               
                        if(PHYLinkState <= LAN8742_STATUS_LINK_DOWN)   // 拔出网线或者是没有插上网线
                        {
                                if(g_ucEthLinkStatus == 2)    // 之前网线是连接上的(或者称之为是插上的)
                                {
                                        {
                                                        g_ucEthLinkStatus =3;
                                                        NX_Debug("LAN8742 LINK DOWM. 3\r\n");   //网线拔掉或者是没有插上
       
                                                        LAN8742_hardware_init_status_set();
                                                        HAL_ETH_Stop_IT(&ETH_Handle);
                                                        DHCP_delete_user();                          //删除 dhcp
                                                        tcp_thread_delete_user();                  //删除 tcp
                                                       
                                                        NX_Debug("delete all ...\r\n");
                                               
                                        }
                                }
                        }
                        else   // 插上 网线
                        {
                                {
                                        if(g_ucEthLinkStatus == 3)
                                        {
                                                g_ucEthLinkStatus = 0;
                                                eth_count = 0;
                                                NX_Debug("LAN8742 LINK UP. 2\r\n");  //网线插上
                                               
                                                tcp_thread_creat_user();  // 重新初始化 tcp, dhcp 等
                                        }
                                }
                        }       

                tx_thread_sleep(1000);   // 1s
        }
}






回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2022-5-31 18:25:29 | 显示全部楼层
程序里面线不做服务器,客户端之类的功能,仅启动NetX和DHCP,插拔网线是否正常。
回复

使用道具 举报

0

主题

5

回帖

5

积分

新手上路

积分
5
发表于 2022-5-31 18:52:44 | 显示全部楼层
DHCP数据包是广播包,可以尝试通过Wireshark抓个包看看,看下第三次是否有发DHCP DISCOVER?没有发出来的话,尝试在这个函数_nx_dhcp_send_request_internal() 里面设个断点,跟踪下哪个地方失败了。方便的话把Wireshark包发处理看一下,另外tcp_thread_creat_user() 代码也发一下看看。
回复

使用道具 举报

610

主题

3060

回帖

4910

积分

至尊会员

积分
4910
 楼主| 发表于 2022-5-31 21:12:14 | 显示全部楼层
本帖最后由 hpdell 于 2022-5-31 21:19 编辑
eric2013 发表于 2022-5-31 18:25
程序里面线不做服务器,客户端之类的功能,仅启动NetX和DHCP,插拔网线是否正常。

我吧 tcp 客户端/服务端 屏蔽,插拔结果还是一样的,貌似感觉是 dhcp 没有启动一样,
  /* wait until an IP address is ready */
  if(tx_semaphore_get(&dhcp_semaphore, TX_WAIT_FOREVER) != TX_SUCCESS)    // 这个地方获取 dhcp 信号量,始终都没有获取到 。。。???
  {
                NX_Debug("dhcp_semaphore get ip...........\r\n");

  }


/**
* @brief  IP address change call back
* @param ip_instance: NX_IP instance registered for this callback
* @param ptr: VOID * optional user data
* @retval none
*/
static VOID ip_address_change_notify_callback(NX_IP *ip_instance, VOID *ptr)   // 这个里面,如果 dhcp 获取 ip 地址成功就会发送信号量 。。。???
{
        tx_semaphore_put(&dhcp_semaphore);
}


// -----------------------------是不是这个 删除不够彻底呀 ??
nx_dhcp_delete(&dhcp_client);


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2022-6-1 09:42:04 | 显示全部楼层
hpdell 发表于 2022-5-31 21:12
我吧 tcp 客户端/服务端 屏蔽,插拔结果还是一样的,貌似感觉是 dhcp 没有启动一样,
  /* wait until a ...

什么时候配套个这种方法就方便了。

【实战经验分享】一劳永逸的解决网线随意热插拔问题
https://www.armbbs.cn/forum.php? ... 5386&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

610

主题

3060

回帖

4910

积分

至尊会员

积分
4910
 楼主| 发表于 2022-6-1 09:48:28 | 显示全部楼层
本帖最后由 hpdell 于 2022-6-1 09:50 编辑
eric2013 发表于 2022-6-1 09:42
什么时候配套个这种方法就方便了。

【实战经验分享】一劳永逸的解决网线随意热插拔问题



终于找到治疗癌症的方法了,原来问题就出在 _nx_driver_hardware_packet_send 这个函数里面

移植 x-cube-azrtos-h7-2.1.0  + HAL v1.11.0 版本的,出现 热插拔 成功 <= 2 次的解决方法

具体如下:
static UINT  _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr)

{

  ... ...


  TxPacketCfg.Length = buffLen;
  TxPacketCfg.TxBuffer = Txbuffer;

        #if   1
        /* Save the packet pointer to release.  
           支持网线 无限制热插拔 , 2022.06.01
        */
                ETH_Handle.TxDescList.CurrentPacketAddress = (uint32_t *)packet_ptr;
        
            /* transmit the packet sws ok */
                if(HAL_ETH_Transmit_IT(D_Handle, &TxPacketCfg))
                {
                        return(NX_DRIVER_ERROR);
                }
               
      /* Remove the Ethernet header.  */
    NX_DRIVER_ETHERNET_HEADER_REMOVE(packet_ptr);

    /* Free the packet.  */
    nx_packet_transmit_release(packet_ptr);        

        #else  // ST 官网  NetX v6.1.11 + HAL v1.11.0

                /* Save the packet pointer to release.  
                   只支持网线 热插拔 <= 2 次,偶尔可能会是3次而已
                */
                TxPacketCfg.pData = (uint32_t *)packet_ptr;   
        
            /* transmit the packet sws ok */
                if(HAL_ETH_Transmit_IT(D_Handle, &TxPacketCfg))
                {
                        return(NX_DRIVER_ERROR);
                }
               
      /* Remove the Ethernet header.  */
    NX_DRIVER_ETHERNET_HEADER_REMOVE(packet_ptr);

    /* Free the packet.  */
    nx_packet_transmit_release(packet_ptr);
        #endif


  return(NX_SUCCESS);
}


#define  LAN8742_RESET_TIME   5*60    // 5分钟

__IO UCHAR g_ucEthLinkStatus = 0;
void ethernetif_set_link(ULONG thread_input)   // 吧这个做成一个任务运行即可
{
       
        NX_PARAMETER_NOT_USED(thread_input);
        ETH_MACConfigTypeDef MACConf = {0};
        int32_t          PHYLinkState;
        int32_t    EthLinkStatus = 0;
        uint32_t linkchanged = 0;
        uint32_t                                                 duplex, speed;
        static uint16_t                 eth_count = 0;
       
       
        // 2022.05.30 add sws
        while(LAN8742_hardware_init_status_get() != 1) {   // 等待 LAN8742 硬件初始化完成
       
                tx_thread_sleep(1000);
        }
               
       
       
        while(1)
        {
                        /* Get link state */
                        PHYLinkState = nx_eth_phy_get_link_state();
                               
                        if(PHYLinkState <= LAN8742_STATUS_LINK_DOWN)
                        {
                                // 没连接上 60s 软件复位一次
                                if(eth_count++ > (LAN8742_RESET_TIME))
                                {
                                        int rst_time = LAN8742_RESET_TIME;
                                        NX_Debug("Reset the LAN8742A chip every %d S once\r\n", rst_time) ;  //每隔 LAN8742_RESET_TIME s 对 LAN8742A 芯片复位一次
                                        eth_count=0;
                                        g_ucEthLinkStatus = 0;
                                        nx_eth_phy_software_reset();                                                       
                                }
                               
                                if (nx_driver_information.nx_driver_information_state >=  NX_DRIVER_STATE_LINK_ENABLED)
                                {
                                        g_ucEthLinkStatus =3;
                                        NX_Debug("LAN8742 LINK DOWM. 3\r\n");   //网线拔掉或者是没有插上
                                        HAL_ETH_Stop_IT(&ETH_Handle);
                                        nx_driver_information.nx_driver_information_state = NX_DRIVER_STATE_INITIALIZED;
                                }
                        }
                        else
                        {
                                if (nx_driver_information.nx_driver_information_state <  NX_DRIVER_STATE_LINK_ENABLED)
                                {
                                        eth_count = 0;
                                        g_ucEthLinkStatus =2;
                                        NX_Debug("LAN8742 LINK UP. 2\r\n");  //网线插上
                                }
                        }

                        switch(g_ucEthLinkStatus)
                        {

                                case 2:
                                        g_ucEthLinkStatus = 0xff;

                                        tcp_thread_creat_user();
                                break;

                                case 3:
                                        g_ucEthLinkStatus = 0xff;
                                        DHCP_delete_user();
                                        tcp_thread_delete_user();
                                break;

                                default : break;
                        }
                tx_thread_sleep(1000);   // 1s
        }       
}


经过实际测试,连续插拔 50 次都没有问题

回复

使用道具 举报

610

主题

3060

回帖

4910

积分

至尊会员

积分
4910
 楼主| 发表于 2022-6-1 16:58:22 | 显示全部楼层
本帖最后由 hpdell 于 2022-6-1 17:00 编辑
chenbo 发表于 2022-5-31 18:52
DHCP数据包是广播包,可以尝试通过Wireshark抓个包看看,看下第三次是否有发DHCP DISCOVER?没有发出来的话 ...

/*
******************************************************************************************

******************************************************************************************
*/
void _nx_driver_stm32h7xx_InitEx(void)
{
UINT    status;
UINT old_priority;
       
                NX_Debug("NX_USER_MODE  == NX_USER_SERVER\r\n");
                NX_Debug("开发板设置为 服务器端\r\n");

                if(netx_init_flag) return;
       
                netx_init_flag = 0xff;
       
                status = NETX_Memory(0);
                if(status == 0)  
                {
                        NX_Debug("nx 内存申请失败 ... ?\r\n");
                        return;
                }
               
    /* Initialize the NetX system.  */
    nx_system_initialize();
       
    /* Create the server packet pool.  */
    status =  nx_packet_pool_create(&nx_packet_pool,     /* 内存池控制块 */
                                                                                                                                                "NetX Main Packet Pool",   /* 内存池名 */
                                                                                                                                                1536,                      /* 内存池每个数据包大小,单位字节
                                                                 此值必须至少为 40 个字节,并且还必须可以被 4 整除 */
//                                                                                                                                                (ULONG*)(((int)packet_pool_area + 15) & ~15) , /* 内存池地址,此地址必须ULONG对齐 */
                                                                                                                                                (ULONG*)packet_pool_area ,   //内存申请方法  ok
                                                                                                                                                NX_PACKET_POOL_SIZE);

    if (status)  /* 检测创建是否失败 */
                {
      NX_Debug("nx_packet_pool_create error ...\r\n");
                        return;
                }                                                                                                       

    /* Create an IP instance.  */
    status = nx_ip_create(&nx_ip,
                          "NetX ip creat thread",

#ifdef NX_ENABLE_DHCP
                          IP_ADDRESS(0,0,0,0),
                          IP_ADDRESS(0,0,0,0),
#else
                          IP_ADDRESS(192, 168, 1, 139),
                          0xFFFFFF00UL,
#endif

                          &nx_packet_pool,
                                                                                                        _nx_driver_stm32h7xx,
                          (UCHAR*)ip_thread_stack,
                          IP_TASK_STACK_SIZE,
                          DEFAULT_PRIORITY);                                                                                                                                                       
                                                                                                       
    if (status)
                {
      NX_Debug("nx_ip_create error = %d...\r\n", status);
                        return;
                }
               

    /* 使能ARP,并提供ARP缓存 for DHCP Server IP.  
                                此函数用于使能 ARP 地址解析
                */
    status =  nx_arp_enable(&nx_ip, (void *)arp_space_area, ARP_SPACE_STACK_SIZE);
    if (status)
                {
      NX_Debug("nx_arp_enable error ...\r\n");
                        return;
                }                                               

    status = nx_icmp_enable(&nx_ip);
    if (status)
                {
      NX_Debug("nx_icmp_enable error ...\r\n");
                        return;
                }
               
               
    /*  使能fragment
                                nx_ip_fragment_enable 此函数用于启用 IPv4 和 IPv6 数据包分段和
                                重组功能。创建 IP 任务时,此服务会自动禁用
                */   
    status = nx_ip_fragment_enable(&nx_ip);
    if (status)
                {
      NX_Debug("nx_ip_fragment_enable error ...\r\n");
                        return;
                }       
               
    /* Enable TCP traffic.  */
    status =  nx_tcp_enable(&nx_ip);
    if (status)
                {
      NX_Debug("nx_tcp_enable error ...\r\n");
                        return;
                }
                                                                                                       
    /* Enable UDP traffic.  */
    status = nx_udp_enable(&nx_ip);
    if (status)
                {
      NX_Debug("nx_udp_enable error ...\r\n");
                        return;
                }       


//                if(eth_link_thread.tx_thread_id == 0)  // 这个任务要一直运行,所以只需创建一次即可
                {
                        static char _init=0;
                        if(!_init) {   // 只初始化一次即可
                                _init = 1;
                                tx_thread_create(&eth_link_thread,
                                                                                                        "eth_link_thread",
                                                                                                        ethernetif_set_link,
                                                                                                        0,
                                                                                                        eth_link_thread_stack,
                                                                                                        APP_TASK_ETH_LINK_STK_SIZE,
                                                                                                        APP_TASK_ETH_LINK_PRIO,
                                                                                                        APP_TASK_ETH_LINK_PRIO,
                                                                                                        TX_NO_TIME_SLICE,
                                                                                                        TX_AUTO_START);                                // 立即启动               
                        }
                }       

    /* NETX初始化完毕后,重新设置优先级 */
    tx_thread_priority_change(netx_thread_ptr, APP_CFG_TASK_NETX_PRIO_1, &old_priority);
    tx_thread_priority_change(&AppTaskNetXTCB, APP_CFG_TASK_NetXPro_PRIO_1, &old_priority);
               
    tx_thread_create(&tcp_thread,
                                                                                        "tcp_thread",
                                                                                        tcp_thread_entry,
                                                                                        0,
                                                                                        server_thread_stack,
                                                                                        APP_TASK_TCP_STK_SIZE,
                                                                                        APP_TASK_TCP_PRIO,
                                                                                        APP_TASK_TCP_PRIO,
                                                                                        TX_NO_TIME_SLICE,
                                                                                        TX_DONT_START);       // 不立即启动


        DHCP_Init();
                                                                                 
}


/*
************************************************************************************************
获取到 ip 地址后恢复 tcp 任务,在 dhcp 任务里面调用
************************************************************************************************
*/
void tcp_thread_creat_user(void)
{
        _nx_driver_stm32h7xx_InitEx();
}
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2022-6-1 19:11:53 | 显示全部楼层
hpdell 发表于 2022-6-1 09:48
终于找到治疗癌症的方法了,原来问题就出在 _nx_driver_hardware_packet_send 这个函数里面

移植  ...

回复

使用道具 举报

610

主题

3060

回帖

4910

积分

至尊会员

积分
4910
 楼主| 发表于 2022-6-2 08:35:58 | 显示全部楼层
回复

使用道具 举报

0

主题

2

回帖

2

积分

新手上路

积分
2
发表于 2023-8-29 14:32:10 | 显示全部楼层
牛!还没看太懂
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-10 17:29 , Processed in 0.393057 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表