? WinCE重置网络的方法--技术天地

WinCE重置網絡的方法

 2016/7/11    

  在實際應用中,復雜的網絡狀況可能讓設備網絡產生異常(比如IP沖突),從而無法正常網絡通信。通過重啟設備可以恢復網絡,本文介紹另外一個方法,在應用層不斷電的情況下快速重置網絡,恢復網絡通信。


手動重置網絡


  進入板子控制面板->網絡和撥號連接,可以看到板子現有網口的網絡連接圖標,下圖以EM9287為例,EM9287有兩個網口,分別為ENET1和ENET2。


1.gif

 

  右鍵點擊需要重置的網口圖標,先選擇禁用,可以看到圖標顯示X,同時板子網絡燈停止閃爍。


1.gif


  再次右鍵點擊該圖標,選擇啟用,圖標恢復連接顯示,可以觀察到板子網絡燈重新亮起。


1.gif


代碼重置網絡


  引用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是有復位的,即網絡在硬件層進行了復位。文中提到的例程,可以通過聯系英創工程師獲得。