2012-07-01 06:51:22 -03:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reactive.Subjects;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using log4net;
|
|
|
|
|
|
|
|
|
|
namespace ArdupilotMega.Presenter
|
|
|
|
|
{
|
|
|
|
|
public class ConfigCameraStabPresenter : INotifyPropertyChanged, IDataErrorInfo
|
|
|
|
|
{
|
|
|
|
|
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
|
|
|
|
|
|
|
|
|
// These are lightweight PropertyMetaData objects, just so that populating defaults
|
|
|
|
|
// and saving etc can be done programatically, rather than explicitely
|
|
|
|
|
// This is starting to step on the toes of PropertyDescriptor etc in System.Componentmodel,
|
|
|
|
|
// however I wanted to keep 'normal' CLR properties here for testability, and more certain Mono
|
|
|
|
|
// compatibility
|
|
|
|
|
private readonly List<PropertyMap> _propertyMap = new List<PropertyMap>
|
|
|
|
|
{
|
|
|
|
|
PropertyMap.Create<int>("CameraPitchMin", "CAM_P_MIN", 1000),
|
|
|
|
|
PropertyMap.Create<int>("CameraPitchMax", "CAM_P_MAX", 2000),
|
|
|
|
|
PropertyMap.Create<int>("CameraPitchTrim", "CAM_P_TRIM", 1500),
|
|
|
|
|
PropertyMap.Create<bool>("CameraPitchReverse", "CAM_P_REV", false),
|
|
|
|
|
PropertyMap.Create<float>("CameraPitchGain", "CAM_P_G", 1.0F),
|
|
|
|
|
PropertyMap.Create<int>("CameraRollMin", "CAM_R_MIN", 1000),
|
|
|
|
|
PropertyMap.Create<int>("CameraRollMax", "CAM_R_MAX", 2000),
|
|
|
|
|
PropertyMap.Create<int>("CameraRollTrim", "CAM_R_TRIM", 1500),
|
|
|
|
|
PropertyMap.Create<bool>("CameraRollReverse", "CAM_R_REV", false),
|
|
|
|
|
PropertyMap.Create<float>("CameraRollGain", "CAM_R_G", 1.0F),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private CameraAxisProperties _pitchAxis;
|
|
|
|
|
private CameraAxisProperties _rollAxis;
|
|
|
|
|
|
|
|
|
|
private readonly IMAVLink _mavlink;
|
|
|
|
|
private readonly Dictionary<string, string> _errors;
|
|
|
|
|
|
|
|
|
|
public ConfigCameraStabPresenter(IMAVLink mavlink)
|
|
|
|
|
{
|
|
|
|
|
_mavlink = mavlink;
|
|
|
|
|
_errors = new Dictionary<string, string>();
|
|
|
|
|
|
|
|
|
|
RefreshValuesCommand = new DelegateCommand(_ => GetCameraStabVals());
|
|
|
|
|
WriteValuesCommand = new DelegateCommand(_ => WriteValues());
|
|
|
|
|
SetDefaultsCommand = new DelegateCommand(_ => SetDefaults());
|
|
|
|
|
|
|
|
|
|
// Todo change to load params once finished
|
|
|
|
|
SetDefaults();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
|
|
|
|
|
|
public ICommand SetDefaultsCommand { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Try to write the cam stab values to the apm
|
|
|
|
|
/// </summary>
|
|
|
|
|
public ICommand WriteValuesCommand { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Re-Fetch the cam stab values from teh apm
|
|
|
|
|
/// </summary>
|
|
|
|
|
public ICommand RefreshValuesCommand { get; private set; }
|
|
|
|
|
|
|
|
|
|
#region publicBindableProperties
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Pitch The lowest PWM
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int CameraPitchMin
|
|
|
|
|
{
|
|
|
|
|
get { return _pitchAxis.Min; }
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_pitchAxis.Min == value) return;
|
|
|
|
|
_pitchAxis.Min = value;
|
|
|
|
|
RaisePropertyChanged("CameraPitchMin");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Pitch The highest PWM
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int CameraPitchMax
|
|
|
|
|
{
|
|
|
|
|
get { return _pitchAxis.Max; }
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_pitchAxis.Max == value) return;
|
|
|
|
|
_pitchAxis.Max = value;
|
|
|
|
|
RaisePropertyChanged("CameraPitchMax");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int CameraPitchTrim
|
|
|
|
|
{
|
|
|
|
|
get { return _pitchAxis.Trim; }
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_pitchAxis.Trim == value) return;
|
|
|
|
|
_pitchAxis.Trim = value;
|
|
|
|
|
RaisePropertyChanged("CameraPitchTrim");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Set higher or lower to scale the travel of the servo
|
|
|
|
|
/// </summary>
|
|
|
|
|
public float CameraPitchGain
|
|
|
|
|
{
|
|
|
|
|
get { return _pitchAxis.Gain; }
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_pitchAxis.Gain == value) return;
|
|
|
|
|
_pitchAxis.Gain = value;
|
|
|
|
|
RaisePropertyChanged("CameraPitchGain");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool CameraPitchReverse
|
|
|
|
|
{
|
|
|
|
|
get { return _pitchAxis.Reverse; }
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_pitchAxis.Reverse == value) return;
|
|
|
|
|
_pitchAxis.Reverse = value;
|
|
|
|
|
RaisePropertyChanged("CameraPitchReverse");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Roll The lowest PWM
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int CameraRollMin
|
|
|
|
|
{
|
|
|
|
|
get { return _rollAxis.Min; }
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_rollAxis.Min == value) return;
|
|
|
|
|
_rollAxis.Min = value;
|
|
|
|
|
RaisePropertyChanged("CameraRollMin");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Roll The highest PWM
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int CameraRollMax
|
|
|
|
|
{
|
|
|
|
|
get { return _rollAxis.Max; }
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_rollAxis.Max == value) return;
|
|
|
|
|
_rollAxis.Max = value;
|
|
|
|
|
RaisePropertyChanged("CameraRollMax");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int CameraRollTrim
|
|
|
|
|
{
|
|
|
|
|
get { return _rollAxis.Trim; }
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_rollAxis.Trim == value) return;
|
|
|
|
|
_rollAxis.Trim= value;
|
|
|
|
|
RaisePropertyChanged("CameraRollTrim");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Set higher or lower to scale the travel of the servo
|
|
|
|
|
/// </summary>
|
|
|
|
|
public float CameraRollGain
|
|
|
|
|
{
|
|
|
|
|
get { return _rollAxis.Gain; }
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_rollAxis.Gain == value) return;
|
|
|
|
|
_rollAxis.Gain = value;
|
|
|
|
|
RaisePropertyChanged("CameraRollGain");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool CameraRollReverse
|
|
|
|
|
{
|
|
|
|
|
get { return _rollAxis.Reverse; }
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_rollAxis.Reverse == value) return;
|
|
|
|
|
_rollAxis.Reverse = value;
|
|
|
|
|
RaisePropertyChanged("CameraRollReverse");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private bool hasError;
|
|
|
|
|
|
|
|
|
|
public bool HasError
|
|
|
|
|
{
|
|
|
|
|
get { return hasError; }
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (hasError == value) return;
|
|
|
|
|
hasError = value;
|
|
|
|
|
RaisePropertyChanged("HasError", false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
private void GetCameraStabVals()
|
|
|
|
|
{
|
|
|
|
|
foreach (var p in _propertyMap)
|
|
|
|
|
{
|
|
|
|
|
var pinfo = GetType().GetProperty(p.PresenterPropertyName);
|
|
|
|
|
var paramVal = GetParam(p.ApmPropertyName, p.PropertyType);
|
|
|
|
|
pinfo.SetValue(this, paramVal, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetDefaults()
|
|
|
|
|
{
|
|
|
|
|
_propertyMap.ForEach(p => GetType().GetProperty(p.PresenterPropertyName).SetValue(this, p.DefaultValue, null));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void WriteValues()
|
|
|
|
|
{
|
|
|
|
|
foreach (var p in _propertyMap)
|
|
|
|
|
{
|
|
|
|
|
var pinfo = GetType().GetProperty(p.PresenterPropertyName);
|
|
|
|
|
var val = pinfo.GetValue(this, null);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// handle boolean
|
|
|
|
|
if (val.GetType() == typeof(Boolean))
|
|
|
|
|
{
|
2012-07-05 20:27:42 -03:00
|
|
|
|
if (!_mavlink.setParam(p.ApmPropertyName, ((Boolean)val) ? 1 : -1))
|
2012-07-01 06:51:22 -03:00
|
|
|
|
log.Error("Error setting Camstab parameter");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!_mavlink.setParam(p.ApmPropertyName, float.Parse(val.ToString())))
|
|
|
|
|
log.Error("Error setting Camstab parameter");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
log.Error("Error setting Camstab parameter", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private object GetParam(string paramName, Type paramType)
|
|
|
|
|
{
|
|
|
|
|
if (_mavlink.param.ContainsKey(paramName))
|
|
|
|
|
{
|
|
|
|
|
return paramType == typeof (bool)
|
|
|
|
|
? _mavlink.param[paramName].ToString() == "1"
|
|
|
|
|
: Convert.ChangeType(_mavlink.param[paramName].ToString(), paramType);
|
|
|
|
|
}
|
|
|
|
|
log.ErrorFormat("Could not get param {0}", paramName);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Load()
|
|
|
|
|
{
|
|
|
|
|
RefreshValuesCommand.Execute(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RaisePropertyChanged(string propName, bool shouldValidate = true)
|
|
|
|
|
{
|
|
|
|
|
if (shouldValidate)
|
|
|
|
|
ValidatePropertyValues();
|
|
|
|
|
|
|
|
|
|
if (PropertyChanged != null)
|
|
|
|
|
{
|
|
|
|
|
PropertyChanged(this, new PropertyChangedEventArgs(propName));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ValidatePropertyValues()
|
|
|
|
|
{
|
|
|
|
|
var errCount = _errors.Count;
|
|
|
|
|
_errors.Clear();
|
|
|
|
|
if (CameraPitchMax < CameraPitchMin)
|
|
|
|
|
{
|
|
|
|
|
_errors["CameraPitchMax"] = "Max should be > Min";
|
|
|
|
|
_errors["CameraPitchMin"] = "Max should be > Min";
|
|
|
|
|
}
|
|
|
|
|
if ((CameraPitchTrim < CameraPitchMin) || (CameraPitchTrim > CameraPitchMax))
|
|
|
|
|
{
|
|
|
|
|
_errors["CameraPitchTrim"] = "Trim should be between Min and Max";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CameraRollMax < CameraRollMin)
|
|
|
|
|
{
|
|
|
|
|
_errors["CameraRollMax"] = "Max should be > Min";
|
|
|
|
|
_errors["CameraRollMin"] = "Max should be > Min";
|
|
|
|
|
}
|
|
|
|
|
if ((CameraRollTrim < CameraRollMin) || (CameraRollTrim > CameraRollMax))
|
|
|
|
|
{
|
|
|
|
|
_errors["CameraRollTrim"] = "Trim should be between Min and Max";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_errors.Count != errCount)
|
|
|
|
|
{
|
|
|
|
|
this.RaisePropertyChanged("Error", false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HasError = _errors.Count > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string this[string columnName]
|
|
|
|
|
{
|
|
|
|
|
get { return _errors.ContainsKey(columnName) ? _errors[columnName] : null; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Error
|
|
|
|
|
{
|
|
|
|
|
get { return _errors.Values.FirstOrDefault(); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private struct CameraAxisProperties
|
|
|
|
|
{
|
|
|
|
|
public int Min;
|
|
|
|
|
public int Max;
|
|
|
|
|
public int Trim;
|
|
|
|
|
public float Gain;
|
|
|
|
|
public bool Reverse;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private struct PropertyMap
|
|
|
|
|
{
|
|
|
|
|
public string PresenterPropertyName;
|
|
|
|
|
public string ApmPropertyName;
|
|
|
|
|
public Type PropertyType;
|
|
|
|
|
public object DefaultValue;
|
|
|
|
|
|
|
|
|
|
public static PropertyMap Create<T>(string presenterPropertyName, string apmPropertyName, object defaultVal)
|
|
|
|
|
{
|
|
|
|
|
return new PropertyMap
|
|
|
|
|
{
|
|
|
|
|
PresenterPropertyName = presenterPropertyName,
|
|
|
|
|
ApmPropertyName = apmPropertyName,
|
|
|
|
|
PropertyType = typeof(T),
|
|
|
|
|
DefaultValue = defaultVal
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|