using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
namespace ArducopterConfigurator.PresentationModels
{
///
/// View Model for the sensors monitor and calibration
///
///
/// This tab is for the monitoring and calibration of the Gyro/Accel sensors
///
/// When it is activated, it retrieves the current sensor calibration values
/// Then, it requests the constant stream of sensor readings in order to provide
/// a live view.
///
/// The user can change the calibration offsets, and upload the new values.
/// When this happens, the model tells the APM to cease sending the realtime updates,
/// then sends the new offset values, then resumes the updates
///
/// There is a command to automatically fill the sensor offset values, from the
/// current values of the sensors. The user would do this when the copter is
/// sitting still and level
///
/// When the VM is deactivated, the model tells the APM to cease sending the realtime updates
///
public class SensorsVm : NotifyProperyChangedBase, IPresentationModel
{
private const string CALIB_REFRESH = "J";
private const string CALIB_UPDATE = "I";
private const string SEND_SENSOR_DATA = "S";
private const string STOP_UPDATES = "X";
private bool waitingForCalibData;
public SensorsVm()
{
RefreshCalibrationOffsetsCommand = new DelegateCommand(_ => RefreshCalibValues());
UpdateCalibrationOffsetsCommand = new DelegateCommand(_ => UpdateCalibValues());
CalculateCalibrationOffsetsCommand = new DelegateCommand(_ => CalcCalibValues());
PropertyChanged += ((sender, e) =>
{
IsArmed = !(MotorFront == 1040 && MotorRear == 1040 && MotorLeft == 1040 && MotorRight == 1040);
});
}
public void RefreshCalibValues()
{
sendString(STOP_UPDATES);
waitingForCalibData = true;
sendString(CALIB_REFRESH);
}
public void UpdateCalibValues()
{
sendString(PropertyHelper.ComposePropValuesWithCommand(this, _calibrationPropsInUpdateOrder, CALIB_UPDATE));
sendString(SEND_SENSOR_DATA);
}
public void CalcCalibValues()
{
AccelRollOffset = AccelRollOffset - AccelRoll;
AccelPitchOffset = AccelPitchOffset - AccelPitch;
//AccelZOffset = AccelZOffset - AccelZ;
FirePropertyChanged("AccelRollOffset");
FirePropertyChanged("AccelPitchOffset");
//FirePropertyChanged("AccelZOffset");
}
public string Name
{
get { return "Sensor Data"; }
}
private readonly string[] _sensorPropsInUpdateOrder = new[]
{
"LoopTime",
"GyroRoll",
"GyroPitch",
"GyroYaw",
"Unused", // Throttle
"ControlRoll", // control roll
"ControlPitch", // control pitch
"ControlYaw", // control yaw
"MotorFront",
"MotorRear",
"MotorRight",
"MotorLeft",
"AccelRoll",
"AccelPitch",
"AccelZ",
"CompassHeading", // AP_Compass.heading
"UnusedFloat", // AP_Compass.heading_x
"UnusedFloat", // AP_Compass.heading_y
"Unused", // AP_Compass.mag_x
"Unused", // AP_Compass.mag_y
"Unused", // AP_Compass.mag_z
};
private readonly string[] _calibrationPropsInUpdateOrder = new[]
{
"GyroRollOffset",
"GyroPitchOffset",
"GyroYawOffset",
"AccelRollOffset",
"AccelPitchOffset",
"AccelZOffset"
};
private void sendString(string str)
{
if (sendTextToApm != null)
sendTextToApm(this, new sendTextToApmEventArgs(str));
}
public void Activate()
{
// Get the calib. data first
waitingForCalibData = true;
sendString(CALIB_REFRESH);
}
public void DeActivate()
{
sendString(STOP_UPDATES);
}
public void handleLineOfText(string strRx)
{
if ( waitingForCalibData)
{
PropertyHelper.PopulatePropsFromUpdate(this, _calibrationPropsInUpdateOrder, strRx, true);
waitingForCalibData = false;
sendString(SEND_SENSOR_DATA);
}
else
{
PropertyHelper.PopulatePropsFromUpdate(this, _sensorPropsInUpdateOrder, strRx, false);
}
}
public event EventHandler updatedByApm;
public event EventHandler sendTextToApm;
public ICommand RefreshCalibrationOffsetsCommand { get; private set; }
public ICommand UpdateCalibrationOffsetsCommand { get; private set; }
public ICommand CalculateCalibrationOffsetsCommand { get; private set; }
#region Calibration Properties
public float GyroRollOffset { get; set; }
public float GyroPitchOffset { get; set; }
public float GyroYawOffset { get; set; }
public float AccelRollOffset { get; set; }
public float AccelPitchOffset { get; set; }
public float AccelZOffset { get; set; }
#endregion
private bool _isArmed;
///
/// Whether the Arducopter is Armed or not
///
///
/// We don't get this information directly, but we can infer it if all motors are
/// at 1040 then the thing is NOT armed.
///
public bool IsArmed
{
get { return _isArmed; }
set
{
if (_isArmed == value) return;
_isArmed = value;
FirePropertyChanged("IsArmed");
}
}
#region Sensor Properties
private int _loopTime;
public int LoopTime
{
get { return _loopTime; }
set
{
if (_loopTime == value) return;
_loopTime = value;
FirePropertyChanged("LoopTime");
}
}
private int motorFront;
public int MotorFront
{
get { return motorFront; }
set {
if (motorFront == value) return;
motorFront = value;
FirePropertyChanged("MotorFront");
}
}
private int motorRear;
public int MotorRear
{
get { return motorRear; }
set
{
if (motorRear == value) return;
motorRear = value;
FirePropertyChanged("MotorRear");
}
}
private int motorLeft;
public int MotorLeft
{
get { return motorLeft; }
set
{
if (motorLeft == value) return;
motorLeft = value;
FirePropertyChanged("MotorLeft");
}
}
private int motorRight;
public int MotorRight
{
get { return motorRight; }
set
{
if (motorRight == value) return;
motorRight = value;
FirePropertyChanged("MotorRight");
}
}
private int gyroPitch;
public int GyroPitch
{
get { return gyroPitch; }
set
{
if (gyroPitch == value) return;
gyroPitch = value;
FirePropertyChanged("GyroPitch");
}
}
private int gyroRoll;
public int GyroRoll
{
get { return gyroRoll; }
set
{
if (gyroRoll == value) return;
gyroRoll = value;
FirePropertyChanged("GyroRoll");
}
}
private int gyroYaw;
public int GyroYaw
{
get { return gyroYaw; }
set
{
if (gyroYaw == value) return;
gyroYaw = value;
FirePropertyChanged("GyroYaw");
}
}
private int accelPitch;
public int AccelPitch
{
get { return accelPitch; }
set
{
if (accelPitch == value) return;
accelPitch = value;
FirePropertyChanged("AccelPitch");
}
}
private int accelRoll;
public int AccelRoll
{
get { return accelRoll; }
set
{
if (accelRoll == value) return;
accelRoll = value;
FirePropertyChanged("AccelRoll");
}
}
private int accelZ;
public int AccelZ
{
get { return accelZ; }
set
{
if (accelZ == value) return;
accelZ = value;
FirePropertyChanged("AccelZ");
}
}
private int _controlRoll;
public int ControlRoll
{
get { return _controlRoll; }
set
{
if (_controlRoll == value) return;
_controlRoll = value;
FirePropertyChanged("ControlRoll");
}
}
private int _controlPitch;
public int ControlPitch
{
get { return _controlPitch; }
set
{
if (_controlPitch == value) return;
_controlPitch = value;
FirePropertyChanged("ControlPitch");
}
}
private int _controlYaw;
public int ControlYaw
{
get { return _controlYaw; }
set
{
if (_controlYaw == value) return;
_controlYaw = value;
FirePropertyChanged("ControlYaw");
}
}
private float _compassHeading;
///
/// The current compass Heading as read from the magnetometer in radians?
///
public float CompassHeading
{
get { return _compassHeading; }
set
{
if (_compassHeading == value) return;
_compassHeading = value;
FirePropertyChanged("CompassHeading");
FirePropertyChanged("CompassHeadingDegrees");
}
}
///
/// The current compass Heading as read from the magnetometer in degrees
///
public float CompassHeadingDegrees
{
get
{
var degrees = (float) ((CompassHeading) * (180 / Math.PI));
return (360 + degrees) % 360;
}
}
#endregion
public int Unused { get; set; }
public float UnusedFloat { get; set; }
}
}