Using the Windows 7 Sensor and Location Platform from C#

Introduction

PCs are very versatile in their connectivity with different devices. For instance with USB alone, you can connect thousands of different devices, many of which could be considered to be sensors of some kind. But what is a sensor, really?

A sensor, in the Windows 7 sense, is a device that is capable of metering the physical outside world. For instance, a sensor could detect the current temperature, ambient light level, location (as in GPS), acceleration in 3D, and so forth. All in all, many different devices fit into this broad definition.

In this article, you will learn about the Sensor and Location Platform, which is part of Windows 7. You will also learn how .NET and C# developers can access the features of this platform from their .NET applications. For instance, .NET 4.0 provides a new namespace that allows you to directly access location sensors using a convenient, managed code API.

This article assumes you are using the Microsoft Visual Studio 2010 Release Candidate (RC) version or later. The new location classes in .NET 4.0 have changed since the previous Beta 2 release, so if you are using the older beta, you will need to adjust the code. As for the sensor examples with Windows API Code Pack, version v1.0.1 was used. Remember that the code pack can be used with both Microsoft Visual Studio 2008 and 2010 (including Beta 2 and RC versions).

Sensor and Location Platform Architecture

Before Windows 7, all different sensor devices, hundreds of them, have more or less had a unique way of controlling them from code. Devices have different physical interfaces, different control commands, and their output is in different format. This makes the life of developers difficult, as each device has to be programmed differently.

The Sensor and Location Platform (SLP) in Windows 7 aims to change this by providing a common program model and driver interface for all sensor (including location) devices (Figure 1). If the device has a Windows 7 SLP compatible driver available (these drivers are user-mode based, and thus can be written more easily than kernel-based drivers), Windows 7 will properly detect the device as a sensor, and then allow the SLP API to access the device.



Figure 1 – Windows 7 has a new Control Panel applet to show sensor and location devices

If compatible devices are present, you can, on the lowest level, use a COM API supported by SLP to communicate with the device. SLP supports a wide range of different device types, and these devices are identified with GUID values.

Support for Sensors and Location in .NET

In Windows 7, the new Sensor and Location Platform API is COM based, meaning that the API is available to both native and managed code applications. As a .NET developer, you could either create your own wrappers around these COM classes and interfaces, or you could use ready-made code.

Currently, you have two basic options, you can use the free Windows API Code Pack to get access to the SLP features, or if you are already using .NET 4.0 with Visual Studio 2010, then you can use the new features in .NET 4.0 to access parts of the functionality provided by SLP.

For those preferring to use .NET 4.0, there is a new namespace called the System.Device.Location. This namespace contains support for Windows 7’s Location APIs, but does not directly support the Sensor platform, at least yet. So, with .NET 4.0 alone, you can use location services (think GPS), but for the rest of the functionality, you need to continue using the Windows API Code Pack.

Since the System.Device.Location is indeed part of .NET 4.0, then technically, you could access the classes and methods even on a Windows XP machine. However, although the .NET classes are available, they will report that the state of the location system is always Disabled, unless you are using Windows 7. Thus, even if the .NET classes are available to you, it doesn’t mean the operating system support is there.

When programming for devices, the common developer question is: can I start developing without real hardware in my hands, and then only later start testing with a real device? The answer is yes, as far as sensors are concerned. The Windows 7 SDK contains a virtual device that emulates a physical light sensor, and has drivers that make Windows 7 think it is a real device. This makes starting development easy.

As for location based services, you currently need to have a physical device in place. Of course, if you had for instance a laptop with a built-in (internal) GPS device and Windows 7 compatible SLP drivers for it, then that would work just as well. But generally speaking, most GPS devices are external.

Getting Started With Sensor Development

To get started with developing sensor applications for the new Sensor and Location Platform with Microsoft Visual Studio, you will need either version 2008 or 2010 (at this writing, the release candidate is the latest 2010 version), the Windows API Code Pack, and, obviously, Windows 7.

If you have a physical sensor device that you can connect to your PC, you are in good hands. If you don’t, then Microsoft refers you to Freescale Semiconductor. They sell a piece of hardware called the Flexis JM Badge Board, which is priced at $49. You can order one directly from Freescale, and this could then be used as basis for your own testing.

For those developers that don’t have a physical device in place but wish to get started with development, they should download and install the Windows 7 SDK kit (Figure 2). It takes a while to install this kit (remember to check whether you need the x86 or x64 version!), but once it is done, you can run the VirtualLightSensor.exe application from the folder Bin under the SDK installation path (by default, C:\Program Files\Microsoft SDKs\Windows\v7.0). This gives you a virtual sensor to program against.



Figure 2 – The Windows 7 SDK kit gives access to a virtual light sensor that is useful when testing code

Note that before you can successfully run the virtual light sensor application, you must install the proper drivers into Windows 7. This can be done from an elevated command prompt with the “pnputil -a VirtualLightSensorDriver.inf” command. You can find the .INF file in the Bin directory of the SDK kit (Figure 3).



Figure 3 – Installing the driver for the virtual light sensor with PnpUtil

Whether you are using a physical sensor or the virtual one provided by the Windows 7 SDK, you should see the device in Control Panel under Location and Other Sensors. Once you can see your device here, you are ready to start programming.

The first step is to create or open a project in Microsoft Visual Studio, for instance a Windows Forms or Windows Presentation Foundation (WPF) application. Then, add a reference to the Windows API Code Pack (see the Resources section for the download URL), and you are set. The DLLs you need to reference are named Microsoft.WindowsAPICodePack.dll and Microsoft.WindowsAPICodePack.Sensors.dll. With the references in place, you can start using the namespace Microsoft.WindowsAPICodePack.Sensors.

This namespace contains a class named SensorManager, with which you can get overall information about the supported sensors in the system. For example:


SensorList<Sensor> sensors =
   SensorManager.GetAllSensors();
MessageBox.Show(“There are ” + sensors.Count +
   ” sensor(s) installed on the system.”);

Once you know that sensors are available on the system (for instance, check the Count property of the above list), you can start using each individual sensor. Sensors have properties with which you can detect their type (what kind of sensor it is) from a pre-defined set of GUIDs. With the Windows API Code Pack, the enumeration SensorTypes lists the available types.

For the virtual light sensor, the type is specified as SensorTypes.AmbientLight. Since the SLP APIs are generic and support many different sensor types, you can either read sensor values in a generic manner, or by typecasting the generic sensor object to a given type. Typecasting allows you to read the values more easily. One of such specific sensor classes is AmbientLightSensor, which is derived from the generic Sensor class.

To get an instance of the ambient light sensor, you could use code like this:


SensorList<AmbientLightSensor> sensors =
 SensorManager.GetSensorsByTypeId<AmbientLightSensor>();
foreach (AmbientLightSensor sensor in sensors)
{
 …
}

Here, the GetSensorsByTypeId method of the SensorManager class accepts a generic type specification, which allows you to have a list of correctly typed sensor objects to work with. There is also a non-generic version of this method available.

To read the current value from a sensor object, you can use the following code:


sensor.UpdateData();
MessageBox.Show(“The sensor \”” +
 sensor.FriendlyName + “\” reports the luminosity ” +
 “value to be ” + sensor.
 CurrentLuminousIntensity.Intensity + ” lux.”);

The light level reported by the virtual light sensor can be controlled through the VirtualLightSensor.exe application (Figure 4). If you change the setting to a certain lux value, the value reported by the above code will change. The actual numeric value is reported by the CurrentLuminousIntensity.Intensity property.



Figure 4. The virtual light sensor control application

The code shown above is good for reading the metered value in a one-off fashion. If you instead prefer to be notified whenever the value changes, you can write an event handler for the sensor object’s DataReportChanged event. You could also check the value of the State property to determine if a value can be read.

Location programming with .NET 4.0

If you are already using Visual Studio 2010 and .NET 4.0, you can test your skills with the new System.Device.Location namespace. Using this namespace requires you to have a compatible device capable of calculating its location. Most often, this would be a GPS device with a USB or Bluetooth connection, but it could also be a mobile device able to detect its location using cell tower triangulation, for instance.

The next section assumes that you have a compatible location device in place. To begin writing code, with Visual Studio 2010, start a new project, and make sure you select .NET 4.0 as your target framework version (Figure 5).



Figure 5. To take best advantage of Windows 7, you need to use .NET 4.0.

In Visual Studio’s Solution Explorer, add a reference to System.Device.dll, and add the appropriate using statement to your code file:


using System.Device.Location;

Now you are ready to start using the classes inside the new namespace. A class named GeoCoordinateWatcher can be considered as a starting point for developers. With this class, you can initiate a location process, and in return get an object of type GeoCoordinate. This object is able to return the location as a conventional latitude and longitude pair.

When using these watcher and coordinate classes, there are two particular details that you need to be aware of. First, there might be multiple location-sensing devices (providers) connected. The GeoCoordinateWatcher class will automatically select the most appropriate location provider based on the required accuracy (which can be set when creating an instance of the watcher), the last time a particular provider could detect its location, and so on. For instance, when moving indoors, a GPS device might no longer be the most accurate provider for location.

Secondly, finding the current location using the device might take a relatively long time, multiple seconds perhaps, or even more if the device has just been powered on. Because of this, the GeoCoordinateWatcher class is usually operated in an asynchronous manner, as not to block the user interface thread of the application.

To achieve asynchronous operation, you can call the Start method of the GeoCoordinateWatcher class to initiate location data acquisition, and then write an event handler for the PositionChanged event. This way, the watcher class will automatically call the event handler once location data becomes available.

The synchronous way of getting the current location can be achieved by calling the TryStart method. This method takes a timeout value as a parameter that indicates how long the method will wait for location data to become available.

Here is how you might use the location based classes to determine the current latitude and longitude asynchronously:


private void button1_Click(
   object sender, EventArgs e)
{
   GeoCoordinateWatcher watcher =
       new GeoCoordinateWatcher();
   watcher.PositionChanged +=
       new EventHandler<GeoPositionChangedEventArgs<
           GeoCoordinate>>(GeoPositionChanged);
   watcher.Start();
}

private void GeoPositionChanged(object sender,
   GeoPositionChangedEventArgs<GeoCoordinate> e)
{
   MessageBox.Show(“The current location is: ” +
       e.Position.Location.Latitude + “/” +
       e.Position.Location.Longitude + “.”);
}


In this code snippet, the determined location is read in the PositionChanged event handler named GeoPositionChanged. The passed event arguments (parameter e) are of type GeoPositionChangedEventArgs<GEOCOORDINATE>, which is a generic type declaration. In this case, the GeoCoordinate class is the type of the Position.Location property. The GeoCoordinate class in turn has two properties of interest: Latitude and Longitude.

In many cases, a latitude/longitude coordinate pair is enough to plot the current location on a map. However, SLP also supports conversion of these coordinates into a so-called civic address, which is a traditional street, city and country type of address. Not all devices or services are able to do such conversions, but if such a service is available, then you can use the CivicAddressResolver class to convert a GeoCoordinate to a civic address.

At this point, you are aware of how you can use the basic classes in the new System.Device.Location namespace to find the user’s current location if suitable devices (providers) are present. However, before concluding, there’s one security related detail you need to be aware of. Location based information is considered sensitive in Windows 7, and thus the user must give his or her consent that the location can be determined.

This is done with a permission dialog box, in a similar fashion to the User Account Control (UAC) prompt, though not as intrusively as the UAC prompt. Once the user gives permission to find the location, the GeoCoordinateWatcher class can operate normally. Otherwise, location data will not be available, just as if there were no location providers connected.

Conclusion

The new Sensor and Location Platform, part of Windows 7, is a nice new addition to the operating system. In the future, especially location will be a major player in successful applications, and thus it is imperative to have an easily programmable interface for location-sensing devices. This way, the developer doesn’t need to learn the specific APIs to access each different device; as such details are enclosed in the user-mode drivers.

The Sensor and Location Platform differentiates devices into two broad classes: those that can sense the physical environment (such as temperature, light level or orientation), and those that can sense location. For sensors, the platform provides a generic API that can be used to query the properties of each device. For location-sensing devices, the platform provides an API through which the latitude and longitude coordinates can be retrieved, and optionally, a civic address (street, city, state, etc.).
In the future, more and more devices will start to include drivers that are compatible with the Sensor and Location Platform. Once this happens, applications that need to sense the environment will be much easier to write.

Resources


Visual Studio 2010 RC download page

Windows API Code Pack download for Visual Studio 2008 and 2010

MSDN documentation for the System.Device.Location namespace

Freescale Semiconductor Flexis JM Badge Board

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read