Windows 7 Sensor and Location API – A Sample Application
In order to learn about sensor development, I decided to do a take on the Sensor Diagnostic Tool application. My application called Sensor Starter is a WPF application that leverages the Sensor Wrapper Library to program to the Sensor API. The User Interface displays the enumerated sensors in a tree control, displays sensor properties and sensor data in a set of grid controls and displays graphical output for each activated sensor on the JM Badge:
Enumerating Sensors
The code to enumerate the sensors is quite simple. The library provides a SensorManager that has a static method called GetAllSensors() that returns an array of Sensor objects:
Sensor[] sensors = SensorManager.GetAllSensors();
Each sensor object is then wrapped in a SensorModel, a class that provides additional sensor processing. The SensorModel is inserted into a Dictionary (m_sensors) indexed by the Sensor ID which is a GUID. Finally the Sensor information is added to the TreeView for display to the user:
for (int i = 0; i < sensors.Length; i++)
{
Sensor s = sensors[i];
m_sensors[s.SensorID] = new SensorModel(s);
TreeViewItem nodeSensor = new TreeViewItem();
nodeSensor.Header = m_sensors[s.SensorID].Sensor.FriendlyName;
nodeSensor.Tag = (object)m_sensors[s.SensorID].Sensor.SensorID;
((TreeViewItem)SensorTreeView.Items[0]).Items.Add(nodeSensor);
}
Hooking into Sensor Events
If the user clicks on one of the Sensors in the list, the DataUpdated Event is hooked into and the application starts to receive a real-time feed from the sensor on a background thread:
// hook up the data update event handler
private void SensorTreeView_SelectedItemChanged( object sender, RoutedPropertyChangedEventArgs<object> e)
{
// selected item in the tree
TreeViewItem t = (TreeViewItem) SensorTreeView.SelectedItem;
// index into the dictionay of sensors
Guid sensorID = (Guid) t.Tag;
//set event handlers for the selected sensor
m_sensors[sensorID].Sensor.DataUpdated += new
SensorDataUpdatedEventHandler(DataUpdatedHandler);
}
// this method will queue up the data update request
// asynchronously using the WPF Dispatcher object
public void DataUpdatedHandler(Sensor sensor, SensorDataReport newData)
{
ThreadStart start = delegate()
{
// use the dispatcher to update UI elements with new data figures
DispatcherOperation op = Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
new Action<Sensor>(UpdateData), sensor);
};
// Create the thread and kick it started!
new Thread(start).Start();
}
Handling Sensor Data and Properties
The UpdateData() method is where all the magic happens. The sensor provides a data report and a property report. This data and properties are translated into DataTables by the SensorModel so that the WPF application can deal with it more easily, binding it to data grids and updating graphical elements on the screen:
// raw data coming back from the sensor
SensorDataReport sensorDataReport;
// raw data mapped to fields
IDictionary<PropertyKey, object> sensorData;
// sensor properties coming back from the sensor
IDictionary<PropertyKey, object> sensorProperties;
sensorDataReport = s.GetDataReport();
sensorData = sensorDataReport.GetDataFields();
sensorProperties = s.GetAllProperties();
//grab the model for the sensor of interest
SensorModel sm = m_sensors[s.SensorID];
// translate the data and properties to DataTable based name, value
// pairs for binding to the grids
DataTable d = sm.XLate(sensorData);
DataTable p = sm.XLate(sensorProperties);
The Location API
The Location API is built on top of the Sensor API and provides two sources of data:
- Civic Address Location
- Longitude, Latitude Location (GPS Device)
The Civic Address Location is the Default Location that the user has entered into the Control Panel à Hardware and Sound à Location and Other Sensors à Default Location screen.
This information is something that users may not want to share with other user accounts and applications so there is a security setting screen on the Control Panel à Hardware and Sound à Location and Sensors à User Settings screen:
If the application has permission, the Civic Address information can be retrieved by requesting a Civic Address Location Report:
CivicAddressDialog d = new CivicAddressDialog(SensorModel.GetCivicAddressReport());
In the Sensor Starter Application, I take this report and display the results in a dialog:
public CivicAddressDialog(CivicAddressLocationReport report)
{
InitializeComponent();
m_report = report;
AddrLine1.Text = m_report.AddressLine1;
AddrLine2.Text = m_report.AddressLine2;
City.Text = m_report.City;
StateProvince.Text = m_report.StateOrProvince;
CountryRegion.Text = m_report.CountryOrRegion;
PostalCode.Text = m_report.PostalCode;
Timestamp.Text = m_report.Timestamp.ToLocalTime().ToString();
DetailLevel.Text = m_report.DetailLevel.ToString();
}
Here is a link to the sample application code: