Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Accelerometer Support on WP7 Emulator

0.00/5 (No votes)
20 Dec 2010 2  
The Windows Phone 7 emulator doesn't support accelerometer. This project will help you to test accelerometer enabled applications on the Windows Phone 7 emulator!

Contents

Introduction

As all we know, there is no support for accelerometer in Windows Phone 7 Emulator. If you are creating some accelerometer bases application, you have to deploy it to your Windows Phone powered device and then test it. Of course, there are projects which are using some hardware such as Wii or XBox 360 controller to emulate mobile device movement. But when you trying to use it occurs that they have one weak point - they needs hardware! Some day, when I had more free time, I decided to find some solution for this. After a couple of hours, I have found one and this is it... I want you to introduce WP7 Accelerometer Emulator project. Let's take a closer look at what it is.

Accelerometer force vectors

Accelerometer force vectors. Source: The windows Phone Developer Blog

How It Works? (End User Perspective)

Solution consists of three projects which are connected each other:

  1. MaciejGrabek.WP7Accelerometer - This is the core library to use in your projects. It contains WP7AccelerometerProvider class which provides all functionality given by real Accelerometer from Microsoft.Devices.Sensors, i.e., Start and Stop methods and ReadingChanged event which provides information about gravity for each axis. There is no IAccelerometer interface to implement, so I simply copied names of all used items from accelerator class manifest.
  2. MaciejGrabek.WP7AccelerometerEmulatorUI - This project allows you to emulate position of phone by simple use of three scrolls for X, Y and Z rotation. It sends all required data to Proxy.
  3. MaciejGrabek.WP7AccelerometerEmulatorProxy - This proxy is used to receive data from UI and allows to read it from WP7AccelerometerProvider.

If you are running your application on emulator, then WP7AccelerometerProvider is trying to read data from Proxy - if something goes wrong on retrieving this data (for example, proxy is unavailable), it simply switches into random data mode. You can retry receiving data from proxy by simple use of Stop and Start methods. Another way is to restart application. Of course, if you will run the application on device it won't use proxy, but it will provide you hardware built in accelerometer data.

How To Use It?

It is very simple - like using real accelerometer.

When you create WP7 application, the first thing you need to do is add a reference to MaciejGrabek.WP7Accelerometer library (or project). Then create an accelerometer object like below:

using MaciejGrabek.WP7Accelerometer;

var acc = new WP7AccelerometerProvider();

Now simply add handling to AccelerometerProviderReadingChanged event and consume data provided by WP7AccelerometerReadingEventArgs class:

acc.ReadingChanged += OnAccelerometerProviderReadingChanged;

private void OnAccelerometerProviderReadingChanged
	(object sender, WP7AccelerometerReadingEventArgs args)
{
    //do what you want with data
    ProcessAccelerometerData(args.X, args.Y, args.Z, args.Timestamp);
}

Start WP7AccelerometerProvider and be ready to get the data.

try
{
    acc.Start();
}
catch (Exception exc)
{
    txtblk.Text = exc.Message;
}

This is all you need to do in the application. Now let's see the control panel. To do this, you need to start MaciejGrabek.WP7AccelerometerEmulatorUI and MaciejGrabek.WP7AccelerometerEmulatorProxy (it should start automatically with MaciejGrabek.WP7AccelerometerEmulatorUI, but if not be sure to do this manually - otherwise you will get random data). Run your WP7 application on emulator and on MaciejGrabek.WP7AccelerometerEmulatorUI mark "Send data to emulator" checkbox and have fun! If you will leave unchecked "Send data to emulator" AccelerometerProvider will simply read what is on proxy without any change on interface. Result is shown below:

WP7 Accelerometer Emulator UI

WP7 Accelerometer Emulator UI

As you can see, it is very simple and intuitive to use.

For the end of this part, let's compare Microsoft.Devices.Sensors.Accelerometer and MaciejGrabek.WP7Accelerometer.WP7AccelerometerProvider:

Accelerometer WP7AccelerometerProvider
public SensorState State { get; }
public SensorState State { get; }
public event EventHandler ReadingChanged; 
//AccelerometerReadingEventArgs
public DateTimeOffset Timestamp { get; }
public double X { get; }
public double Y { get; }
public double Z { get; }
public event EventHandler ReadingChanged; 
//WP7AccelerometerReadingEventArgs
public DateTimeOffset Timestamp { get; }
public double X { get; }
public double Y { get; }
public double Z { get; }
public void Dispose();
public void Dispose();
public void Start();
public void Start();
public void Stop();
public void Stop();

As you can see, both classes are very similar. There is no interface to implement (for example IAccelerometer) so the only way was to create "similar" class. This is all that is important for the "end user" of this emulator. Now let's see how it really works. :)

Under the Hood

First of all, I should explain a little bit more about data flow in this project. As you can see below, the main communication is one way. It means that all that is important for UI project is to send data to the proxy. From other side, the WP7AccelerometerProvider is responsible to read this data from proxy or from device (which has higher priority).

Proxy

As a proxy, I decided to use WCF service that allows to get data using simple "HTTP GET". Here is how service contract and its implementation look.

[ServiceContract(Namespace = "http://maciejgrabek.com/WP7AccelerometerEmulatorProxy")]
public interface IAccelerometerEmulatorProxy
{
    [OperationContract]
    [WebGet]
    string GetData();

    [OperationContract]
    void SetData(float x, float y, float z);
}
[AspNetCompatibilityRequirements(RequirementsMode = 
	AspNetCompatibilityRequirementsMode.Allowed)]
public class AccelerometerEmulatorProxy : IAccelerometerEmulatorProxy
{
    public string GetData()
    {
        AccelerometerVector v = HttpRuntime.Cache
        	[AccelerometerVector.CacheKey] as AccelerometerVector;
        if (v != null)
        {
            return v.ToString();
        }
        else
        {
            return AccelerometerVector.Empty.ToString();
        }
    }
    
    public void SetData(float x, float y, float z)
    {
        AccelerometerVector v = new AccelerometerVector()
        {
            X = x,
            Y = y,
            Z = z
        };
        HttpRuntime.Cache.Remove(AccelerometerVector.CacheKey);
        HttpRuntime.Cache.Add(AccelerometerVector.CacheKey,
            v,
            null,
            DateTime.MaxValue,
            Cache.NoSlidingExpiration,
            CacheItemPriority.Default,
            delegate { });
    }
}

The important thing is to use [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] and [WebGet] to enable this kind of communication with WCF service.
As you can see, to store data from UI, I am using built in cache because it is quick and efficient. The whole logic is not any kind of rocket science, because I followed the "Keep It Simple" rule. :)

UI

On MaciejGrabek.WP7AccelerometerEmulatorUI, there are some XNA classes based calculations, which are required to get proper values of gravity force base vectors. 3D graphic computations are quite a different topic so I will let it for XNA fans. After all operations data is sent to Proxy where it is stored and ready to transfer to Windows Phone Emulator. All these calculations and data transfer is executed 10 times per second. If you want to change, there is method called InitializeAndRunTimer where you can change frequency of timer, but I thing that 10Hz is quite ok.

private void InitializeAndRunTimer()
{
    _timer = new DispatcherTimer();
    _timer.Interval = TimeSpan.FromMilliseconds(100);
    _timer.Tick += delegate
    {
        PerformSingleStep();
    };
    _timer.Start();
}

Core

This is the time to see the core library which is responsible for reading data from "proper" source. Of course, I am thinking about MaciejGrabek.WP7Accelerometer and WP7AccelerometerProvider class. As I mentioned before, it is similar to real Accelerometer definition. The most important thing is to recognize current environment. You can use in this case Microsoft.Devices.Environment.DeviceType property and Microsoft.Devices.DeviceType enumerator. If it is equal to DeviceType.Device, then we are using Accelerometer, otherwise (DeviceType.Emulator) we are initializing WebClient to get data from Proxy. As an example, we can use Stop() method implementation:

[SecuritySafeCritical]
public void Stop()
{
    if (Microsoft.Devices.Environment.DeviceType == DeviceType.Device)
    {
        _accelerometer.Stop();
    }
    else
    {
        this._timer.Stop();
    }
}

When you are creating WP7AccelerometerProvider instance, you can specify two parameters. First of them is dataUrl with default value http://localhost:9876/AccelerometerEmulatorProxy.svc/GetData and the second one is refreshRate which is set to 100 (it means 10Hz). Of course, there is no sense to set this value less than 33, because current display refresh rate is 33 times per second so even if we will read data, it won't be visible for user.

When I was testing this application, I found some caching problem on emulator or web server side. Even if the data was changed on server, there was no way to get new version of it. That was the reason to use little trick:

if (!this._dataUrlError)
{
    if (!this._client.IsBusy)
        this._client.DownloadStringAsync(new Uri(String.Format("{0}?{1}", 
		this._dataUrl, this._rand.NextDouble())), null);
}

When we add some random item to URL, then we can be sure that our request will return not cached data. If there is some problem with data reading from proxy WP7AccelerometerProvider is using Random generator to get some data. Only way to retry reading from proxy is to call Stop() and Start() methods on WP7AccelerometerProvider instance or simply restarting application.

Where To Find It?

I have attached code with binaries, but I will modify and extend it in future. If you want to get current version, you can simply download MaciejGrabek.WP7AccelerometerEmulator and use it in your projects. I will put all updates of code on this place so if you are interested follow project site. There is, of course, some demo to see exactly how to use it and it is attached to the provided solution.

What Will Appear in Future Versions?

  1. Sometimes, you can see Gimbal Lock effect - I am currently trying to solve it
  2. Add mouse control for rotation
  3. Add movement sequences (you can record movement like shaking, rolling, etc., save it, and quick run every time you need)
  4. Add additional acceleration for movement (shake, etc.)

Fell free to comment!

Useful Links

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here