Wednesday, January 20, 2010

How to toggle the Wi-fi radio

I had a task to complete today where I was to create an application to toggle the Wi-Fi radio. I had two major requirements for this task; I was supposed to not spend more an hour on this and it must run on older devices running Pocket PC 2003 (or older)

This is what I came up with, 1 function (the entry point) and it uses only 3 power management API calls; GetDevicePower, DevicePowerNotify, and SetDevicePower

Basically I spent most of the time finding the device name for the wireless device. It seems to be pretty used for Intermec devices as I tested it on 3 different devices (or it could also be that only those 3 devices used the same device name)

Anyway, here's the code (works only for Intermec devices):

#include <windows.h>
#include <pm.h>
 
#define INTERMEC_WIFI_DEVICE    L"{98C5250D-C29A-4985-AE5F-AFE5367E5006}\\BCMCF1"
 
int _tmain(int argc, _TCHAR* argv[])
{
    CEDEVICE_POWER_STATE state;
    GetDevicePower(INTERMEC_WIFI_DEVICE, POWER_NAME, &state);
    CEDEVICE_POWER_STATE newState = (state == D0) ? D4 : D0;
 
    DevicePowerNotify(INTERMEC_WIFI_DEVICE, newState, POWER_NAME);
    SetDevicePower(INTERMEC_WIFI_DEVICE, POWER_NAME, newState);
}


Normally when I experiment with the platform SDK, I just create native console applications and test how the function works. Since my application was simple and didn't need a UI, I just shipped it in native code.

But for the sake of sharing knowledge I ported my tiny application to the .NET Compact Framework. Here's the code (works only for Intermec devices):

[DllImport("coredll.dll", SetLastError = true)]
static extern int DevicePowerNotify(string name, CEDEVICE_POWER_STATE state, int flags);
 
[DllImport("coredll.dll", SetLastError = true)]
static extern int SetDevicePower(string pvDevice, int dwDeviceFlags, CEDEVICE_POWER_STATE DeviceState);
 
[DllImport("coredll.dll", SetLastError = true)]
static extern int GetDevicePower(string pvDevice, int dwDeviceFlags, ref CEDEVICE_POWER_STATE pDeviceState);
 
enum CEDEVICE_POWER_STATE : int
{
    PwrDeviceUnspecified = -1,
    D0 = 0,
    D1 = 1,
    D2 = 2,
    D3 = 3,
    D4 = 4,
    PwrDeviceMaximum = 5
}
 
const int POWER_NAME = 0x00000001;
const string ADAPTER_NAME = "{98C5250D-C29A-4985-AE5F-AFE5367E5006}\\BCMCF1";
 
static void Main()
{
    CEDEVICE_POWER_STATE state = CEDEVICE_POWER_STATE.PwrDeviceUnspecified;
    GetDevicePower(ADAPTER_NAME, POWER_NAME, ref state);
    CEDEVICE_POWER_STATE newState = (state == CEDEVICE_POWER_STATE.D0)
        ? CEDEVICE_POWER_STATE.D4
        : CEDEVICE_POWER_STATE.D0;
 
    DevicePowerNotify(ADAPTER_NAME, newState, POWER_NAME);
    SetDevicePower(ADAPTER_NAME, POWER_NAME, newState);
}


There are smarter, better, and non-OEM specific ways to do this, both in native and managed code. In native code, one can use the wireless device functions (GetWirelessDevice, ChangeRadioState, FreeDeviceList) in ossvcs.dll as described in this article. And in managed code, one can take advantage of the OpenNETCF Smart Device Framework.

Here's an example of how to use the OpenNETCF.WindowsMobile namespace in the Smart Device Framework for toggling the state of wireless devices:

using System.Linq;
using OpenNETCF.WindowsMobile;
 
static class Program
{
    static void Main()
    {
        var wifi = from radio in Radios.GetRadios()
                   where radio.RadioType == RadioType.WiFi
                   select radio;
 
        foreach (var radio in wifi)
            radio.RadioState = (radio.RadioState == RadioState.On) ? RadioState.On : RadioState.Off;
    }
}


I hope you found this article useful

11 comments:

കുട്ടിച്ചാത്തന്‍ said...

Hello sir,
I don't know whether you have comment tracking for old posts so asking a question related to your old post -- http://christian-helle.blogspot.com/2007/06/copying-files-from-device-to-desktop.html here.

your program works fine for me but instead of that how can I make use of CeCopyFile()?
I tried but though it returns 0 fail to copy the file. but if I am giving the same inputs to CeCopyFile() to your function CopyFromDevice it works!

Thanks in advance

Christian Resma Helle said...

CeCopyFile copies an existing file on the remote device to a new file on the remote device

What I do is read the file on the remote device and write the stream to a local file on the desktop machine

കുട്ടിച്ചാത്തന്‍ said...

thank you very much
I misunderstood that it(CeCopyFile) can be used directly to copy file from remote device to desktop

Raffaele Limosani said...

Thanks Christian! I also wanted to explore the same some time ago.. Pls allow me to mention my post http://blogs.msdn.com/raffael/archive/2009/02/27/wireless-programming-on-windows-mobile-supported-or-not-supported.aspx.

Cheers,
~raffaele

Christian Resma Helle said...

Thanks for the link Raffaele!

Anonymous said...

That will work for the Intermec CN3 and CN4 devices (they use the same broadcom radio) but not all Intermec devices.

For a more general solution, you can find the name of the wireless device in the registry:

[HKLM]\System\CurrentControlSet\Control\Power\State

and

[HKLM]\Software\Drivers\WLAN\AdapterName

-PaulH

Ricc said...

I am using embedded visual basic 3 (sorry it's an old app and I cannot rewrite-convert it to .net or c++) running on Windows Mobile 6 (CE 5.2.1711)

can I have an help about how to disable-enable wifi only using simple api calls?
(api declaration, and how to read the device name on registry)

I am in trouble... :-(

thank you!

Ricc

Christian Resma Helle said...

Thanks for the info PaulH

ricc said...

Declare Function SetDevicePower Lib "Coredll" (ByVal pvDevice As String, ByVal dwDeviceFlags As Integer, ByVal DeviceState As Long) As Long

it works!

I still need to read the devicename from the registry, but it's a simpler question...
thanx

Eitan said...

how to disable/enable WIFI on Windows-CE ?
need C# sample code

thanks in advance

Anonymous said...

Hi there, this is very interesting.

Do you know if it's possible to control the phone radio on/off too via code or registry settings?

A supplier has developed an app which runs full screen and communicates via GPRS - for some reason the phone functionality can go 'off' and thus Internet connection is down, I'd like for the phone to be forced ON on device boot or when supplier's app launches - they don't think it's possible but I'm trying to help them out.

Appreciate any guidance you give, thank you.

Chris