using System; using System.Diagnostics; using System.Text; namespace ArducopterConfigurator { /// /// Monitor VM base class /// /// /// Common base for some factored out things like only passing data to an active /// Monitor, etc /// public abstract class MonitorVm : NotifyProperyChangedBase, IPresentationModel { private readonly IComms _sp; protected bool isActive; protected string[] PropsInUpdateOrder; protected MonitorVm(IComms sp) { _sp = sp; _sp.LineOfDataReceived += sp_LineOfDataReceived; } void sp_LineOfDataReceived(string obj) { if (isActive) OnStringReceived(obj); } /// /// Called when the mode is selected /// /// /// Any initialising commands should be sent to the serial port /// when this method is called. /// public void Activate() { isActive = true; OnActivated(); } public void DeActivate() { isActive = false; OnDeactivated(); } protected virtual void OnDeactivated() { } protected virtual void OnActivated() { } /// /// Send raw text to the Arducopter /// protected void SendString(string strToSend) { if (_sp.IsConnected) _sp.Send(strToSend); } /// /// Call-back for text sent back from the Arducopter /// /// /// This is called when a full line of text is received from the APM /// This will not be called when the mode is not selected /// protected abstract void OnStringReceived(string strReceived); #region Implementation of IPresentationModel public abstract string Name { get; } #endregion // Common method for populating properties, using a hardcoded // property update order, and reflection to get the property type protected void PopulatePropsFromUpdate(string strRx, bool fireInpc) { var strs = strRx.Split(','); if (PropsInUpdateOrder.Length!=strs.Length) { Console.WriteLine("Processing update with " + strs.Length + " values, but have " + PropsInUpdateOrder.Length + " properties to populate. Ignoring this update"); return; } for (int i = 0; i < PropsInUpdateOrder.Length; i++) { var prop = this.GetType().GetProperty(PropsInUpdateOrder[i]); var s = strs[i]; object value = null; if (prop == null) { Console.WriteLine("Trying to set non existant property: " + PropsInUpdateOrder[i]); break; } if (prop.PropertyType == typeof(float)) { float val; if (!float.TryParse(s, out val)) { Console.WriteLine("Error parsing float: {0}, VM: {1}" + s, Name); break; } value = val; } if (prop.PropertyType == typeof(bool)) { float val; if (!float.TryParse(s, out val)) { Console.WriteLine("Error parsing float (bool): {0}, VM: {1}" + s, Name); break; } value = val != 0.0; } if (prop.PropertyType == typeof(int)) { int val; if (!int.TryParse(s, out val)) { Console.WriteLine("Error parsing int:{0}, VM: {1}" + s, Name); break; } value = val; } prop.SetValue(this, value, null); if (fireInpc) FirePropertyChanged(PropsInUpdateOrder[i]); } } // Common method for sending/updating data // sentence sent to APM is the commandChar followed by the property // vals in the correct order, seperated by semicolons protected void SendPropsWithCommand(string commandChar) { var strings = new string[PropsInUpdateOrder.Length]; for (int i = 0; i < PropsInUpdateOrder.Length; i++) { var prop = this.GetType().GetProperty(PropsInUpdateOrder[i]); if (prop.PropertyType == typeof(bool)) strings[i] = ((bool) prop.GetValue(this, null)) ? "1" : "0"; else strings[i] = prop.GetValue(this, null).ToString(); } var sentence = commandChar + string.Join(";", strings); SendString(sentence); } } }