After a quick overview of the Sensor and Location Platform - I Can Feel You – Using the Windows 7 Sensor Platform, it is time to start digging into the API. We’ll start with an overview of the Win32 API to understand the data flow and then will review the managed API via the Windows API Code Pack for the .NET Framework.
The Sensor and Location platform has two components, the sensor piece and, built on top of that, the location piece. We’ll cover the sensor piece in great detail to make sure that when the time comes to speak about location, we understand the foundation upon which it is built.
The Sensor API (as well as the Location API) is COM-based. You will find all the required API and GUID definitions in the Sensorsapi.h and Sensors.h files found in your local Windows 7 SDK install. The Sensors.h file contains a ton of GUIDs that define all the different aspects of a sensor’s categories, types, and data. The API and interface are found in the Sensorsapi.h file. A closer look at the Sensorsapi.h file reveals three main COM Interfaces that you should be aware of when working with Sensors:
You will need to work with these three interfaces to integrate sensors into your application.
Integrating Sensors into Your Application
When integrating sensors into your application, you need to follow three basic steps:
Discovering Sensors
The first step you need to take for each application for which you want to use sensors is to discover which sensors are connected to the platform and then get access to one. To enable your application to do this, you need to use the ISensorManager COM Interface. The sensor manager maintains the list of available sensors. Since it is a COM interface, you need to initialize it using CoCreateInstance. You can think of this interface as the root interface for the sensor API. The following code snippet creates an instance of the sensor manager:
// Declare a smart pointer to receive the sensor manager interface pointer.
// Originally, this smart pointer is defined in the class prototype definition
// CAmbientLightAwareSensorManagerEvents
CComPtr<ISensorManager> m_spISensorManager;
HRESULT hr;
// Create the sensor manager
hr = m_spISensorManager.CoCreateInstance(CLSID_SensorManager);
The ISensorManager interface provides a set of methods for discovering and retrieving available sensors. It also exposes an event that is used for receiving notifications when a new sensor becomes available. You may ask yourself where to register for the event where a sensor “leaves” the system. Well, this can be found within the sensor itself. With an ISensorManager pointer at hand, you can start searching for sensors. ISensorManager has three methods that help you search for connected sensors:
As you noticed, all function names reflect that there are multiple sensors connected at the same time to the computer. It is possible that several sensors of the same category are connected to the same PC. For example, on my machine, I have one light sensor built into the PC enclosure and another one as part of my Sensor Development Kit. It makes sense to use the light sensor built in to the enclosure because it provides the most accurate lighting condition reading from the PC. For an application, the best way to discover sensors is to use the Sensor Manager interface's type and category functions and then choose the sensor you need to work with from the list.
Through this series of posts, we’ll use a very simple Microsoft Foundation Classes (MFC) light-aware application that is part of the Windows 7 SDK. The following code is taken from the Initialize method of the CAmbientLightAwareSensorManagerEvents class. This class implements the ISensorManagerEvents interface notifications from the platform upon arrival of a new sensor.
The Initialize method is called during the initialization process of the main dialog (we have only one):
HRESULT CAmbientLightAwareSensorManagerEvents::Initialize()
{
if (SUCCEEDED(hr))
hr = m_spISensorManager->SetEventSink(this);
// Find all Ambient Light Sensors
CComPtr<ISensorCollection> spSensors;
hr = m_spISensorManager->GetSensorsByType
(SENSOR_TYPE_AMBIENT_LIGHT, &spSensors);
if (SUCCEEDED(hr) && NULL != spSensors)
ULONG ulCount = 0;
hr = spSensors->GetCount(&ulCount);
for(ULONG i=0; i < ulCount; i++)
CComPtr<ISensor> spSensor;
hr = spSensors->GetAt(i, &spSensor);
// Helper function that sets up event sinking
// for a specific sensor
hr = AddSensor(spSensor);
// Check the current sensor state.
SensorState state = SENSOR_STATE_READY;
hr = spSensor->GetState(&state);
if(SUCCEEDED(hr))
if(state == SENSOR_STATE_READY)
// Read the sensor data and update the
// application's UI
hr = m_pSensorEvents->GetSensorData
(spSensor);
}
return hr;
Here you can see how, after successfully obtaining an ISensorManager interface, you call ISensorManager::GetSensorsByType, passing SENSOR_TYPE_AMBIENT_LIGHT and a pointer to an ISensorCollection collection, spSensors. The SENSOR_TYPE_AMBIENT_LIGHT indicates that we want to receive only ambient light sensors (ALS). At the same time, you could ask for all sensors of the type SENSOR_TYPE_VOLTAGE from the electrical category, or SENSOR_TYPE_ACCELEROMETER_3D from the motion category.
If successful, the GetSensorsByType function fills ISensorCollection with a list of ALS. Next, you iterate through the sensor collection and call the AddSensor helper function for each sensor. This sets up event sinking (a delegate) by registering the sensor to m_pSensorEvents, which is a SensorEvents implementation class used for event sinking that I’ll explain later. Finally, you call another helper method, GetSensorData, to read data from the sensor and to update the LUX value in the application’s UI. We’ll address the actual reading of sensor data in future posts.
During an application's runtime, new light sensors might get connected to the PC, so you need a mechanism for notifying applications when new sensor devices are connected. The ISensorManager interface contains a SetEventSink method to set an event sinking implementation class – that is, a delegate that handles the events. This function receives an ISensorManagerEvents callback interface that receives the event notifications when a new sensor device is connected. This event sink acts as a listener that handles OnSensorEnter, the only event the ISensorManagerEvents interface has.
If you take a look at the above sample, you will see that you call SetEventSink right after the successful creation of the ISensorManager interface and pass “this” as the input parameter, and then the local class CAmbientLightAwareSensorManagerEvents implements the ISensorManagerEvents interface.
Therefore, in this class you can find the implementation for the ISensorManager::OnSensorEnter event, which looks like the following code snippet:
HRESULT CAmbientLightAwareSensorManagerEvents::OnSensorEnter
(ISensor* pSensor, SensorState state)
HRESULT hr = S_OK;
if (NULL != pSensor)
SENSOR_TYPE_ID idType = GUID_NULL;
hr = pSensor->GetType(&idType);
// we are interested only in light sensors
if (IsEqualIID(idType, SENSOR_TYPE_AMBIENT_LIGHT))
hr = AddSensor(pSensor);
if (SENSOR_STATE_READY == state)
hr = m_pSensorEvents->GetSensorData(pSensor);
else
hr = E_POINTER;
In this code you can see that the OnSensorEnter method receives a pointer to the newly connected sensor device and the state status of the sensor. If the sensor pointer is valid (not null), you first read the sensor’s type by calling the GetType method on the ISensor interface. Because we are in a light-aware application and are interested only in light sensors, we’ll check if the newly connected sensor device is a light sensor by checking its type. Remember that ISensorManager receives notification of any type of sensor devices that are connected to the PC. Assuming the sensor is a light sensor, you then call the same AddSensor helper function that you used in the Initialize method to set up event sinking for specific sensors. (Don’t get confused with the ISensorManager event sinking.) The last thing you do is check whether the sensor is in a ready state. If it is, you read the sensor’s data and update the application’s UI.
But we'll save reading sensor data for our next posts.
You can find more Windows 7 Sensor and Location training at the Channel 9 Learning Center.