Using Sensors in You Application – Managed Part 1

Using Sensors in You Application – Managed Part 1

  • Comments 1
  • Likes

So far we covered the Windows 7 Sensor and Location Platform architecture (I Can Feel You – Using the Windows 7 Sensor Platform), and Using Sensors in Your Application – Native Part 1. This post introduces the managed API for using sensors. In future posts I’ll continue with the native API.

So far, you have seen C++ and COM examples of the Sensor and Location platform. Now let’s take a look at how managed code developers can use the platform, using the Windows API Code Pack for the .NET Framework, to discover and work with sensors.

Discovering Sensors Using Managed Code

Follow the same guidelines in managed code as you would in native code: first discover sensors, next check their state and request permissions if needed, and then read data from the sensor. Let’s start by discovering sensors.

The main namespace for sensors in the Windows API Code Pack is Microsoft.WindowsAPICodePack.Sensors as implemented in the Microsoft.WindowsAPICodePack.Sensors.dll assembly. This namespace contains the SensorManager class that manages the sensor devices that are connected to the PC. This class exposes a set of methods that are similar to those of the native ISensorManager interface. These methods include GetSensorsByCategoryId, GetSensorsByTypeId, and GetSensorsBySensorId, the last of which receives as an input parameter a GUID that either represents a sensor category, type, or single sensor ID. In addition, you can also find the GetAllSensors method, which returns all the sensors that are connected to the system regardless of type or category, as shown by the following code snippet.

private void PrintAllSensors()
{
    SensorList<Sensor> sensorList =  SensorManager.GetAllSensors();
    foreach (var sensor in sensorList)
    {
        StringBuilder sb = new  StringBuilder();
        sb.Append("Sensor Information:");
        sb.Append(Environment.NewLine);
        sb.Append(sensor.FriendlyName);
        sb.Append(Environment.NewLine);
        sb.Append(sensor.CategoryId);
        sb.Append(Environment.NewLine);
        sb.Append(sensor.State);
        sb.Append(Environment.NewLine);
 
        Console.WriteLine(sb.ToString());
    }
}

Running the above code snippet on my local dev machine yields the following output, showing the sensors installed on my local machine. Note that only the virtual light is Ready and the rest are showing AccessDenied indicating that they are not enabled.

Sensor Information:
Legacy GPS Driver
bfa794e4-f964-4fdb-90f6-51056bfe4b44
AccessDenied
 
Sensor Information:
Skyhook Wireless XPS Location Sensor
bfa794e4-f964-4fdb-90f6-51056bfe4b44
AccessDenied
 
Sensor Information:
Ambient Light Sensor
17a665c0-9063-4216-b202-5c7a255e18ce
Ready

 

Since the Windows API Code Pack includes the strongly typed sensor class Sensor, it is easy to get a list of sensors and print their various properties. The native API has a Sensor interface through which you work with sensors, but anything beyond that ISensor Interface requires you to use GUIDs. The Windows API Code Pack provides a list of all the GUIDs that are available in Sensors.h. The SensorPropertyKeys and SensorCategories classes contain the public read-only property of GUID objects that correspond to the same values in the Sensors.h file. However, this is not the usual or preferred programming model that .NET developers are accustomed to, mainly because the native sensor objects are not strongly typed and you have to use the more generic GUID system to access a sensor’s data. This doesn’t allow you to use all the great features .NET offers, such as data binding, type safety, and properties. Therefore, the Microsoft.WindowsAPICodePack.Sensors namespace, described in the image to the right, includes several strongly typed sensor classes that allow you to bind to their properties. For example, you can find AmbientLightSensor, which has one public property, CurrentLuminousIntensity, which represents the current amount of light (luminosity) detected by the sensors. The namespace also includes the interop layer that wraps the native interface, all the metadata information, and the object model that developers work with.

 

Codepack_Sensor

Please note that the Microsoft.WindowsAPICodePack.Sensors namespace offers an extensibility model that allows you to create any strongly typed sensor. When this is combined with the extensibility offered by the native API, you can create any type of sensor you want with any data values. You can read more about the Sensor and Location platform extensibility module at the Sensor and Location Platform Web site: http://www.microsoft.com/whdc/device/sensors/.

With a strongly typed sensor class, the Windows API Code pack can define a .NET Generics version of the Get methods. For example, GetSensorsByTypeId<S>, where S is a type derived from the Sensor base class. The prototype looks like this:

public static SensorList<S> GetSensorsByTypeId<S>( ) where S: Sensor

When using this function, you need to predefine a specific SensorList<> of the desired sensor type, (AmbientLightSensor, in our example), and then call the method requesting the sensor’s manager to return only AmbientLightSensor sensors. The following code snippet illustrates this process:

// Strongly typed SensorList of type AmbientLightSensor
SensorList<AmbientLightSensor> alsList = null;
try
{
    alsList = SensorManager.GetSensorsByTypeId<AmbientLightSensor>();
}
catch (SensorPlatformException) 
{
    //handle error when no sensor device is accessible 
}

The SensorManager class contains one event called SensorChanged, which is equivalent to the native ISensorManager::OnSensorEnter event. The one main difference between the native and managed code implementations is that the managed code implementation, in addition to receiving an event when a new sensor device is connected to the PC, also generates an event when a sensor gets disconnected. Therefore, SensorsChangedEventArgs, the arguments passed to the SensorManager.SensorChanged event handler, includes a SensorAvailabilityChange member that defines the type of change for each sensor, which can be Addition for new sensor devices and Removal when sensors are disconnected from the PC.

SensorManager_SensorsChanged is the function that handles the SensorsChanged event in our application, and it looks like this:

void SensorManager_SensorsChanged( SensorsChangedEventArgs change )
{
    // The SensorsChanged event comes in on a non-UI thread. 
    // Whip up an anonymous delegate to handle the UI update.
    BeginInvoke( new MethodInvoker( delegate
    {
        PopulatePanel( );
    } ) );
}
The SensorsChanged event is dispatched on a different thread than the application’s main form (UI) thread. Windows Forms does not allow you to update the UI of the application from a non-UI thread. Therefore, for any Windows application with a window-based UI, we highly recommend that you use a different thread than the main UI thread to execute long computations or any I/O-bound communication (as we do in our example of how to synchronously read sensor data). Therefore, to properly handle non-UI-thread UI updates, you should use BeginInvoke to execute the specified delegate asynchronously on the thread upon which the form’s underlying handle was created. This is also true for any WPF application. The PopulatePanel method iterates through all the ambient light sensors and updates the application UI as it verifies the sensor state and reads its data. We'll cover this in future posts.
1 Comments
You must be logged in to comment. Sign in or Join Now
  • thank you so very much but i still have problems with Microsoft.WindowsAPICodePack.Sensors , m getting some kind of error codes. il be leaving error code next time i try that out.

    thanks