Reputation: 13537
I'd like to be able to simulate the compass sensor when running a Windows Phone 7.1 in the emulator.
At this stage I don't particularly care what data the compass returns. Just that I can run against something when using the emulator to test the code in question.
I'm aware that I could deploy to my dev unlocked phone to test compass functionality but I've found the connection via the Zune software to drop out frequently.
Update
I've looked into creating my own wrapper class that could simulate the compass when running a debug build and the compass isn't otherwise supported.
The Microsoft.Devices.Sensors.CompassReading struct has me a bit stumpted. Because it is a struct where the properties can only be set internally I can't inherit from it to provide my own values back. I looked at using reflection to brute force some values in but Silverlight doesn't appear to allow it.
Upvotes: 1
Views: 650
Reputation: 4532
as you already noticed I had a similar problem. when I mocked the compass sensor, I also had difficulties because you cannot inherite from the existing classes and write your own logic. Therefore I wrote my own compass interface which is the only compass functionality used by my application. Then there are two implementations, one wrapper to the WP7 compass functionalities and my mock compass.
I can show you some code, but not before weekend as I'm not at my delevopment machine atm.
Edit:
You already got it but for other people who have the same problem I'll add my code. As I already said, I wrote an interface and two implementations, one for the phone and a mock implementation.
Compass Interface
public interface ICompass
{
#region Methods
void Start();
void Stop();
#endregion
#region Properties
CompassData CurrentValue { get; }
bool IsDataValid { get; }
TimeSpan TimeBetweenUpdates { get; set; }
#endregion
#region Events
event EventHandler<CalibrationEventArgs> Calibrate;
event EventHandler<CompassDataChangedEventArgs> CurrentValueChanged;
#endregion
}
Used data classes and event args
public class CompassData
{
public CompassData(double headingAccurancy, double magneticHeading, Vector3 magnetometerReading, DateTimeOffset timestamp, double trueHeading)
{
HeadingAccuracy = headingAccurancy;
MagneticHeading = magneticHeading;
MagnetometerReading = magnetometerReading;
Timestamp = timestamp;
TrueHeading = trueHeading;
}
public CompassData(CompassReading compassReading)
{
HeadingAccuracy = compassReading.HeadingAccuracy;
MagneticHeading = compassReading.MagneticHeading;
MagnetometerReading = compassReading.MagnetometerReading;
Timestamp = compassReading.Timestamp;
TrueHeading = compassReading.TrueHeading;
}
#region Properties
public double HeadingAccuracy { get; private set; }
public double MagneticHeading { get; private set; }
public Vector3 MagnetometerReading { get; private set; }
public DateTimeOffset Timestamp { get; private set; }
public double TrueHeading { get; private set; }
#endregion
}
public class CompassDataChangedEventArgs : EventArgs
{
public CompassDataChangedEventArgs(CompassData compassData)
{
CompassData = compassData;
}
public CompassData CompassData { get; private set; }
}
WP7 implementation
public class DeviceCompass : ICompass
{
private Compass _compass;
#region Implementation of ICompass
public void Start()
{
if(_compass == null)
{
_compass = new Compass {TimeBetweenUpdates = TimeBetweenUpdates};
// get TimeBetweenUpdates because the device could have change it to another value
TimeBetweenUpdates = _compass.TimeBetweenUpdates;
// attach to events
_compass.CurrentValueChanged += CompassCurrentValueChanged;
_compass.Calibrate += CompassCalibrate;
}
_compass.Start();
}
public void Stop()
{
if(_compass != null)
{
_compass.Stop();
}
}
public CompassData CurrentValue
{
get { return _compass != null ? new CompassData(_compass.CurrentValue) : default(CompassData); }
}
public bool IsDataValid
{
get { return _compass != null ? _compass.IsDataValid : false; }
}
public TimeSpan TimeBetweenUpdates { get; set; }
public event EventHandler<CalibrationEventArgs> Calibrate;
public event EventHandler<CompassDataChangedEventArgs> CurrentValueChanged;
#endregion
#region Private methods
private void CompassCalibrate(object sender, CalibrationEventArgs e)
{
EventHandler<CalibrationEventArgs> calibrate = Calibrate;
if (calibrate != null)
{
calibrate(sender, e);
}
}
private void CompassCurrentValueChanged(object sender, SensorReadingEventArgs<CompassReading> e)
{
EventHandler<CompassDataChangedEventArgs> currentValueChanged = CurrentValueChanged;
if (currentValueChanged != null)
{
currentValueChanged(sender, new CompassDataChangedEventArgs(new CompassData(e.SensorReading)));
}
}
#endregion
}
Mock implementation
public class MockCompass : ICompass
{
private readonly Timer _timer;
private CompassData _currentValue;
private bool _isDataValid;
private TimeSpan _timeBetweenUpdates;
private bool _isStarted;
private readonly Random _random;
public MockCompass()
{
_random = new Random();
_timer = new Timer(TimerEllapsed, null, Timeout.Infinite, Timeout.Infinite);
_timeBetweenUpdates = new TimeSpan();
_currentValue = new CompassData(0, 0, new Vector3(), new DateTimeOffset(), 0);
}
#region Implementation of ICompass
public void Start()
{
_timer.Change(0, (int)TimeBetweenUpdates.TotalMilliseconds);
_isStarted = true;
}
public void Stop()
{
_isStarted = false;
_timer.Change(Timeout.Infinite, Timeout.Infinite);
_isDataValid = false;
}
public CompassData CurrentValue
{
get { return _currentValue; }
}
public bool IsDataValid
{
get { return _isDataValid; }
}
public TimeSpan TimeBetweenUpdates
{
get { return _timeBetweenUpdates; }
set
{
_timeBetweenUpdates = value;
if (_isStarted)
{
_timer.Change(0, (int) TimeBetweenUpdates.TotalMilliseconds);
}
}
}
public event EventHandler<CalibrationEventArgs> Calibrate;
public event EventHandler<CompassDataChangedEventArgs> CurrentValueChanged;
#endregion
#region Private methods
private void TimerEllapsed(object state)
{
_currentValue = new CompassData(_random.NextDouble()*5,
(_currentValue.MagneticHeading + 0.1)%360,
_currentValue.MagnetometerReading,
new DateTimeOffset(DateTime.UtcNow),
(_currentValue.TrueHeading + 0.1)%360);
_isDataValid = true;
EventHandler<CompassDataChangedEventArgs> currentValueChanged = CurrentValueChanged;
if(currentValueChanged != null)
{
currentValueChanged(this, new CompassDataChangedEventArgs(_currentValue));
}
}
#endregion
}
Upvotes: 2