WinCE重置网络的方法_技术文章_行业资讯_武汉华和机电技术有限公司
设为首页 | 加入收藏 | 联系我们
  • 解决方案
  • 杆塔betway体育
  • 机械安控
  • 扬尘betway体育
  • 边坡betway体育
  • 大坝betway体育
  • 高支模betway体育
  • 基坑betway体育
  • 建筑betway体育
  • 桥梁betway体育
  • 隧道betway体育
  • 成功案例
  • 服务中心
  • 个性服务
  • 技术支持
  • 资源下载
  • 关于华和
  • 华和介绍
  • 华和历程
  • 联系华和
  • 人才招聘
  • 行业资讯
    information center
    技术文章
    当前位置:首页 > 行业资讯 > 技术文章
    WinCE重置网络的方法
    作者:华和技术 点击量: 发布时间:2017-04-15

    在实际应用中,复杂的网络状况可能让设备网络产生异常(比如IP冲突),从而无法正常网络通信。通过重启设备可以恢复网络,本文介绍另外一个方法,在应用层不断电的情况下快速重置网络,恢复网络通信。

    手动重置网络

    进入板子控制面板->网络和拨号连接,可以看到板子现有网口的网络连接图标,下图以EM9287为例,EM9287有两个网口,分别为ENET1和ENET2。

    右键点击需要重置的网口图标,先选择禁用,可以看到图标显示X,同时板子网络灯停止闪烁。

    再次右键点击该图标,选择启用,图标恢复连接显示,可以观察到板子网络灯重新亮起。

    代码重置网络
    引用pw.h头文件,添加定义板子DEVICEIOCONTROL的相关宏定义。

      #define DD_NDIS_DEVICE_NAME      TEXT("NDS0:")
      #define NDISPWR_DEVICE_NAME     TEXT("NPW1:")

      #define _NDIS_CONTROL_CODE(request,method) \
          CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD, request, method, FILE_ANY_ACCESS)

      #define WINCE_IOCTL_START 8
      #define IOCTL_NDIS_BIND_ADAPTER         _NDIS_CONTROL_CODE( WINCE_IOCTL_START+4, METHOD_OUT_DIRECT )
      #define IOCTL_NDIS_UNBIND_ADAPTER       _NDIS_CONTROL_CODE( WINCE_IOCTL_START+5, METHOD_OUT_DIRECT )
      #define IOCTL_NDIS_GET_ADAPTER_BINDINGS _NDIS_CONTROL_CODE( WINCE_IOCTL_START+8, METHOD_OUT_DIRECT )

      #define FSCTL_NDISPWR_BASE      FILE_DEVICE_NETWORK
      #define _NDISPWR_CTL_CODE(_Function, _Method, _Access)  \
          CTL_CODE(FSCTL_NDISPWR_BASE, _Function, _Method, _Access)
      #define IOCTL_NPW_SAVE_POWER_STATE  \
          _NDISPWR_CTL_CODE(0x200, METHOD_BUFFERED, FILE_ANY_ACCESS)

    首先调用电源管理设备NPW,通知它关闭网口电源(这里以ENET1为例)

      hNdisPwr = CreateFile(NDISPWR_DEVICE_NAME, 0, 0, NULL, OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, INVALID_HANDLE_VALUE);
     
      SavePowerState.CePowerState   = D4;
      SavePowerState.pwcAdapterName = L”ENET1”;
       bRet = DeviceIoControl(
           hNdisPwr,
           IOCTL_NPW_SAVE_POWER_STATE,
           &SavePowerState,
           sizeof(NDISPWR_SAVEPOWERSTATE),
           NULL,
           0x00,
           NULL,
           NULL); 
       CloseHandle(hNdisPwr);

    如果网口有自己的电源管理,那么那么还应该调用以下代码。还是以ENET1为例,这里的字符串一定得是{98C5250D-C29A-4985-AE5F-AFE5367E5006}\ENET1这样的,并且需要两个\0结尾!

      TCHAR                szName[MAX_PATH]=L”ENET1”;     
       int                  nChars;     
       nChars = _sntprintf(
           szName,
           MAX_PATH-1,
           _T("%s\\%s"),
           PMCLASS_NDIS_MINIPORT,
           wcName);
       szName[MAX_PATH-1]=0;
       DWORD dwRet;
       dwRet = SetDevicePower(szName, POWER_NAME, D4);

    通知系统UNBIND网口

      BOOL DoNdisIOControl(DWORD dwCommand, LPVOID pInBuffer,
                      DWORD cbInBuffer, LPVOID pOutBuffer,
                       DWORD * pcbOutBuffer)
      {
        HANDLE hNdis;
        BOOL fResult = FALSE;
               hNdis = ::CreateFile(DD_NDIS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
               FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
               0, NULL);
           if (INVALID_HANDLE_VALUE != hNdis)
           {
               fResult = DeviceIoControl(hNdis, dwCommand, pInBuffer, cbInBuffer,
                   pOutBuffer, (pcbOutBuffer ? *pcbOutBuffer : 0),
                   pcbOutBuffer, NULL);
               CloseHandle(hNdis);
           }
           return fResult;
      }
      …
      bRet = DoNdisIOControl(
          IOCTL_NDIS_UNBIND_ADAPTER,
          wcName,
          (_tcslen(wcName)+2) * sizeof(TCHAR),
          NULL,
          NULL);

    查询网络,确认一下禁用网络是否成功

      bRet = DoNdisIOControl(
           IOCTL_NDIS_GET_ADAPTER_BINDINGS,
           wcName,
           (_tcslen(wcName)+1) * sizeof(TCHAR),
           multiSz,
           &cbBuffer);
           return (multiSz[0] != L'\0');

    让板子网口重新上电,这里上电不能直接使用D0,只能使用默认值PwrDeviceUnspecified

    hNdisPwr = CreateFile(NDISPWR_DEVICE_NAME, 0, 0, NULL, OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, INVALID_HANDLE_VALUE);
     
       SavePowerState.CePowerState   = PwrDeviceUnspecified;
       SavePowerState.pwcAdapterName = L”ENET1”;
       bRet = DeviceIoControl(
           hNdisPwr,
           IOCTL_NPW_SAVE_POWER_STATE,
           &SavePowerState,
           sizeof(NDISPWR_SAVEPOWERSTATE),
           NULL,
           0x00,
           NULL,
           NULL); 
           CloseHandle(hNdisPwr);

       TCHAR                szName[MAX_PATH]=L”ENET1”;     
       int                  nChars;     
       nChars = _sntprintf(
           szName,
           MAX_PATH-1,
           _T("%s\\%s"),
           PMCLASS_NDIS_MINIPORT,
           wcName);
       szName[MAX_PATH-1]=0;
       DWORD dwRet;
       dwRet = SetDevicePower(szName, POWER_NAME, PwrDeviceUnspecified);

      通知系统BIND网口

      bRet = DoNdisIOControl(
           IOCTL_NDIS_BIND_ADAPTER,
           wcName,
           (_tcslen(wcName)+2) * sizeof(TCHAR),
           NULL,
           NULL);

    查询网络,确认一下网络启动是否成功

      bRet = DoNdisIOControl(
           IOCTL_NDIS_GET_ADAPTER_BINDINGS,
           wcName,
           (_tcslen(wcName)+1) * sizeof(TCHAR),
           multiSz,
           &cbBuffer);
           return (multiSz[0] != L'\0');

    例程里已经将以上代码封装到enet.h,使用以下代码可以简单重置网络

      #include "enet.h"
     
       Void ResetENET()
      {
        EnableENET(FALSE);
        EnableENET(TRUE);
      }

    在重置网络前,建议先关闭该网口现有的socket连接

    整个重置过程是通过电源管理将网口断电,然后通知系统将网络UNBIND。然后重新给网口上电,再通知系统将网络BIND。通过网络灯可以看到,硬件PHY是有复位的,即网络在硬件层进行了复位。文中提到的例程,可以通过联系英创工程师获得。