| /* |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| |
| using System; |
| using System.Collections.Generic; |
| using System.Runtime.Serialization; |
| using System.Threading; |
| using Microsoft.Devices.Sensors; |
| using System.Globalization; |
| using System.Diagnostics; |
| |
| namespace WPCordovaClassLib.Cordova.Commands |
| { |
| /// <summary> |
| /// Captures device motion in the x, y, and z direction. |
| /// </summary> |
| public class Accelerometer : BaseCommand |
| { |
| #region AccelerometerOptions class |
| /// <summary> |
| /// Represents Accelerometer options. |
| /// </summary> |
| [DataContract] |
| public class AccelerometerOptions |
| { |
| /// <summary> |
| /// How often to retrieve the Acceleration in milliseconds |
| /// </summary> |
| [DataMember(IsRequired = false, Name = "frequency")] |
| public int Frequency { get; set; } |
| |
| /// <summary> |
| /// Watcher id |
| /// </summary> |
| [DataMember(IsRequired = false, Name = "id")] |
| public string Id { get; set; } |
| |
| /// <summary> |
| /// Creates options object with default parameters |
| /// </summary> |
| public AccelerometerOptions() |
| { |
| this.SetDefaultValues(new StreamingContext()); |
| } |
| |
| /// <summary> |
| /// Initializes default values for class fields. |
| /// Implemented in separate method because default constructor is not invoked during deserialization. |
| /// </summary> |
| /// <param name="context"></param> |
| [OnDeserializing()] |
| public void SetDefaultValues(StreamingContext context) |
| { |
| this.Frequency = 10000; |
| } |
| } |
| |
| #endregion |
| |
| #region Status codes and Constants |
| |
| public const int Stopped = 0; |
| public const int Starting = 1; |
| public const int Running = 2; |
| public const int ErrorFailedToStart = 3; |
| |
| public const double gConstant = -9.81; |
| |
| #endregion |
| |
| #region Static members |
| |
| /// <summary> |
| /// Status of listener |
| /// </summary> |
| private static int currentStatus; |
| |
| /// <summary> |
| /// Accelerometer |
| /// </summary> |
| private static Microsoft.Devices.Sensors.Accelerometer accelerometer = new Microsoft.Devices.Sensors.Accelerometer(); |
| |
| private static DateTime StartOfEpoch = new DateTime(1970, 1, 1, 0, 0, 0); |
| |
| #endregion |
| |
| /// <summary> |
| /// Sensor listener event |
| /// </summary> |
| private void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e) |
| { |
| this.SetStatus(Running); |
| |
| PluginResult result = new PluginResult(PluginResult.Status.OK, GetCurrentAccelerationFormatted()); |
| result.KeepCallback = true; |
| DispatchCommandResult(result); |
| } |
| |
| /// <summary> |
| /// Starts listening for acceleration sensor |
| /// </summary> |
| /// <returns>status of listener</returns> |
| public void start(string options) |
| { |
| if ((currentStatus == Running) || (currentStatus == Starting)) |
| { |
| return; |
| } |
| try |
| { |
| lock (accelerometer) |
| { |
| accelerometer.CurrentValueChanged += accelerometer_CurrentValueChanged; |
| accelerometer.Start(); |
| this.SetStatus(Starting); |
| } |
| |
| long timeout = 2000; |
| while ((currentStatus == Starting) && (timeout > 0)) |
| { |
| timeout = timeout - 100; |
| Thread.Sleep(100); |
| } |
| |
| if (currentStatus != Running) |
| { |
| this.SetStatus(ErrorFailedToStart); |
| DispatchCommandResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, ErrorFailedToStart)); |
| return; |
| } |
| } |
| catch (Exception) |
| { |
| this.SetStatus(ErrorFailedToStart); |
| DispatchCommandResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, ErrorFailedToStart)); |
| return; |
| } |
| PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT); |
| result.KeepCallback = true; |
| DispatchCommandResult(result); |
| } |
| |
| public void stop(string options) |
| { |
| if (currentStatus == Running) |
| { |
| lock (accelerometer) |
| { |
| accelerometer.CurrentValueChanged -= accelerometer_CurrentValueChanged; |
| accelerometer.Stop(); |
| this.SetStatus(Stopped); |
| } |
| } |
| DispatchCommandResult(new PluginResult(PluginResult.Status.OK)); |
| } |
| |
| /// <summary> |
| /// Formats current coordinates into JSON format |
| /// </summary> |
| /// <returns>Coordinates in JSON format</returns> |
| private string GetCurrentAccelerationFormatted() |
| { |
| // convert to unix timestamp |
| // long timestamp = ((accelerometer.CurrentValue.Timestamp.DateTime - StartOfEpoch).Ticks) / 10000; |
| // Note: Removed timestamp, to let the JS side create it using (new Date().getTime()) -jm |
| // this resolves an issue with inconsistencies between JS dates and Native DateTime |
| string resultCoordinates = String.Format("\"x\":{0},\"y\":{1},\"z\":{2}", |
| (accelerometer.CurrentValue.Acceleration.X * gConstant).ToString("0.00000", CultureInfo.InvariantCulture), |
| (accelerometer.CurrentValue.Acceleration.Y * gConstant).ToString("0.00000", CultureInfo.InvariantCulture), |
| (accelerometer.CurrentValue.Acceleration.Z * gConstant).ToString("0.00000", CultureInfo.InvariantCulture)); |
| return "{" + resultCoordinates + "}"; |
| } |
| |
| /// <summary> |
| /// Sets current status |
| /// </summary> |
| /// <param name="status">current status</param> |
| private void SetStatus(int status) |
| { |
| currentStatus = status; |
| } |
| } |
| } |
| |