From 49cab74e780a0259533ad03dc9b2ffcc0144eed5 Mon Sep 17 00:00:00 2001
From: Adam M Rivera <a432511@gmail.com>
Date: Sun, 29 Apr 2012 19:32:33 -0500
Subject: [PATCH] Planner: Added dynamic controls based on the parameter meta
 data that is parsed from the codebase.

---
 .../ArdupilotMegaPlanner/ArdupilotMega.csproj |  32 +-
 .../Controls/IDynamicParameterControl.cs      |  26 ++
 .../Controls/RangeControl.Designer.cs         | 136 +++++++
 .../Controls/RangeControl.cs                  |  73 ++++
 .../Controls/RangeControl.resx                | 120 ++++++
 .../Controls/ValuesControl.Designer.cs        | 105 +++++
 .../Controls/ValuesControl.cs                 |  37 ++
 .../Controls/ValuesControl.resx               | 120 ++++++
 .../ConfigFriendlyParams.Designer.cs          |  93 +++++
 .../ConfigurationView/ConfigFriendlyParams.cs | 382 ++++++++++++++++++
 .../ConfigFriendlyParams.resx                 | 120 ++++++
 .../GCSViews/ConfigurationView/Setup.cs       |   5 +-
 Tools/ArdupilotMegaPlanner/MAVLink.cs         |   7 +
 Tools/ArdupilotMegaPlanner/MainV2.cs          |  29 +-
 .../Utilities/ParameterMetaDataConstants.cs   |  10 +
 15 files changed, 1279 insertions(+), 16 deletions(-)
 create mode 100644 Tools/ArdupilotMegaPlanner/Controls/IDynamicParameterControl.cs
 create mode 100644 Tools/ArdupilotMegaPlanner/Controls/RangeControl.Designer.cs
 create mode 100644 Tools/ArdupilotMegaPlanner/Controls/RangeControl.cs
 create mode 100644 Tools/ArdupilotMegaPlanner/Controls/RangeControl.resx
 create mode 100644 Tools/ArdupilotMegaPlanner/Controls/ValuesControl.Designer.cs
 create mode 100644 Tools/ArdupilotMegaPlanner/Controls/ValuesControl.cs
 create mode 100644 Tools/ArdupilotMegaPlanner/Controls/ValuesControl.resx
 create mode 100644 Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigFriendlyParams.Designer.cs
 create mode 100644 Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigFriendlyParams.cs
 create mode 100644 Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigFriendlyParams.resx

diff --git a/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj b/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj
index ef0b3a082..e773c32e8 100644
--- a/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj
+++ b/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj
@@ -226,6 +226,25 @@
     <Compile Include="Attributes\DisplayTextAttribute.cs" />
     <Compile Include="Attributes\PrivateAttribute.cs" />
     <Compile Include="CodeGen.cs" />
+    <Compile Include="Controls\IDynamicParameterControl.cs" />
+    <Compile Include="GCSViews\ConfigurationView\ConfigFriendlyParams.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="GCSViews\ConfigurationView\ConfigFriendlyParams.Designer.cs">
+      <DependentUpon>ConfigFriendlyParams.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Controls\RangeControl.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Controls\RangeControl.Designer.cs">
+      <DependentUpon>RangeControl.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Controls\ValuesControl.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Controls\ValuesControl.Designer.cs">
+      <DependentUpon>ValuesControl.cs</DependentUpon>
+    </Compile>
     <Compile Include="Utilities\CollectionExtensions.cs" />
     <Compile Include="Utilities\ParameterMetaDataConstants.cs" />
     <Compile Include="Controls\BackstageView\BackstageView.cs">
@@ -692,6 +711,9 @@
     <EmbeddedResource Include="GCSViews\ConfigurationView\ConfigRawParams.resx">
       <DependentUpon>ConfigRawParams.cs</DependentUpon>
     </EmbeddedResource>
+    <EmbeddedResource Include="GCSViews\ConfigurationView\ConfigFriendlyParams.resx">
+      <DependentUpon>ConfigFriendlyParams.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="GCSViews\ConfigurationView\ConfigTradHeli.es-ES.resx">
       <DependentUpon>ConfigTradHeli.cs</DependentUpon>
     </EmbeddedResource>
@@ -734,6 +756,12 @@
     <EmbeddedResource Include="GCSViews\ConfigurationView\ConfigAccelerometerCalibrationPlane.zh-TW.resx">
       <DependentUpon>ConfigAccelerometerCalibrationPlane.cs</DependentUpon>
     </EmbeddedResource>
+    <EmbeddedResource Include="Controls\RangeControl.resx">
+      <DependentUpon>RangeControl.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Controls\ValuesControl.resx">
+      <DependentUpon>ValuesControl.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="GCSViews\ConfigurationView\Setup.resx">
       <DependentUpon>Setup.cs</DependentUpon>
     </EmbeddedResource>
@@ -1077,7 +1105,9 @@
     <None Include="AeroSimRCAPMHil.zip">
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </None>
-    <None Include="app.config" />
+    <None Include="app.config">
+      <SubType>Designer</SubType>
+    </None>
     <None Include="arducopter-xplane.zip">
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </None>
diff --git a/Tools/ArdupilotMegaPlanner/Controls/IDynamicParameterControl.cs b/Tools/ArdupilotMegaPlanner/Controls/IDynamicParameterControl.cs
new file mode 100644
index 000000000..b87c75e0c
--- /dev/null
+++ b/Tools/ArdupilotMegaPlanner/Controls/IDynamicParameterControl.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace ArdupilotMega.Controls
+{
+   public interface IDynamicParameterControl
+   {
+      /// <summary>
+      /// Gets the name.
+      /// </summary>
+      /// <value>
+      /// The name.
+      /// </value>
+      string Name { get; set; }
+
+      /// <summary>
+      /// Gets the value.
+      /// </summary>
+      /// <value>
+      /// The value.
+      /// </value>
+      string Value { get; set; }
+   }
+}
diff --git a/Tools/ArdupilotMegaPlanner/Controls/RangeControl.Designer.cs b/Tools/ArdupilotMegaPlanner/Controls/RangeControl.Designer.cs
new file mode 100644
index 000000000..75772de32
--- /dev/null
+++ b/Tools/ArdupilotMegaPlanner/Controls/RangeControl.Designer.cs
@@ -0,0 +1,136 @@
+namespace ArdupilotMega.Controls
+{
+   partial class RangeControl
+   {
+      /// <summary> 
+      /// Required designer variable.
+      /// </summary>
+      private System.ComponentModel.IContainer components = null;
+
+      /// <summary> 
+      /// Clean up any resources being used.
+      /// </summary>
+      /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+      protected override void Dispose(bool disposing)
+      {
+         if (disposing && (components != null))
+         {
+            components.Dispose();
+         }
+         base.Dispose(disposing);
+      }
+
+      #region Component Designer generated code
+
+      /// <summary> 
+      /// Required method for Designer support - do not modify 
+      /// the contents of this method with the code editor.
+      /// </summary>
+      private void InitializeComponent()
+      {
+         this.trackBar1 = new System.Windows.Forms.TrackBar();
+         this.label1 = new System.Windows.Forms.Label();
+         this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
+         this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
+         this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
+         this.myLabel1 = new ArdupilotMega.Controls.MyLabel();
+         ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit();
+         this.tableLayoutPanel1.SuspendLayout();
+         this.tableLayoutPanel2.SuspendLayout();
+         ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
+         this.SuspendLayout();
+         // 
+         // trackBar1
+         // 
+         this.trackBar1.Location = new System.Drawing.Point(77, 3);
+         this.trackBar1.Name = "trackBar1";
+         this.trackBar1.Size = new System.Drawing.Size(179, 30);
+         this.trackBar1.TabIndex = 3;
+         // 
+         // label1
+         // 
+         this.label1.AutoSize = true;
+         this.label1.Location = new System.Drawing.Point(3, 5);
+         this.label1.Name = "label1";
+         this.label1.Size = new System.Drawing.Size(35, 13);
+         this.label1.TabIndex = 4;
+         this.label1.Text = "label1";
+         // 
+         // tableLayoutPanel1
+         // 
+         this.tableLayoutPanel1.AutoSize = true;
+         this.tableLayoutPanel1.ColumnCount = 1;
+         this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
+         this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0);
+         this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 1);
+         this.tableLayoutPanel1.Location = new System.Drawing.Point(4, 33);
+         this.tableLayoutPanel1.Name = "tableLayoutPanel1";
+         this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(0, 5, 0, 10);
+         this.tableLayoutPanel1.RowCount = 2;
+         this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
+         this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
+         this.tableLayoutPanel1.Size = new System.Drawing.Size(471, 70);
+         this.tableLayoutPanel1.TabIndex = 5;
+         // 
+         // tableLayoutPanel2
+         // 
+         this.tableLayoutPanel2.ColumnCount = 2;
+         this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F));
+         this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 75F));
+         this.tableLayoutPanel2.Controls.Add(this.trackBar1, 1, 0);
+         this.tableLayoutPanel2.Controls.Add(this.numericUpDown1, 0, 0);
+         this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 21);
+         this.tableLayoutPanel2.Name = "tableLayoutPanel2";
+         this.tableLayoutPanel2.RowCount = 1;
+         this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
+         this.tableLayoutPanel2.Size = new System.Drawing.Size(298, 36);
+         this.tableLayoutPanel2.TabIndex = 5;
+         // 
+         // numericUpDown1
+         // 
+         this.numericUpDown1.Location = new System.Drawing.Point(3, 3);
+         this.numericUpDown1.Name = "numericUpDown1";
+         this.numericUpDown1.Size = new System.Drawing.Size(47, 20);
+         this.numericUpDown1.TabIndex = 4;
+         // 
+         // myLabel1
+         // 
+         this.myLabel1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+         this.myLabel1.Location = new System.Drawing.Point(4, 4);
+         this.myLabel1.Name = "myLabel1";
+         this.myLabel1.resize = false;
+         this.myLabel1.Size = new System.Drawing.Size(227, 23);
+         this.myLabel1.TabIndex = 0;
+         this.myLabel1.Text = "myLabel1";
+         // 
+         // RangeControl
+         // 
+         this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+         this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+         this.AutoSize = true;
+         this.Controls.Add(this.tableLayoutPanel1);
+         this.Controls.Add(this.myLabel1);
+         this.Name = "RangeControl";
+         this.Size = new System.Drawing.Size(478, 106);
+         ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).EndInit();
+         this.tableLayoutPanel1.ResumeLayout(false);
+         this.tableLayoutPanel1.PerformLayout();
+         this.tableLayoutPanel2.ResumeLayout(false);
+         this.tableLayoutPanel2.PerformLayout();
+         ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
+         this.ResumeLayout(false);
+         this.PerformLayout();
+
+      }
+
+      #endregion
+
+      private ArdupilotMega.Controls.MyLabel myLabel1;
+      private System.Windows.Forms.TrackBar trackBar1;
+      private System.Windows.Forms.Label label1;
+      private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
+      private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
+      private System.Windows.Forms.NumericUpDown numericUpDown1;
+
+   }
+}
diff --git a/Tools/ArdupilotMegaPlanner/Controls/RangeControl.cs b/Tools/ArdupilotMegaPlanner/Controls/RangeControl.cs
new file mode 100644
index 000000000..2781d0df6
--- /dev/null
+++ b/Tools/ArdupilotMegaPlanner/Controls/RangeControl.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace ArdupilotMega.Controls
+{
+   public partial class RangeControl : UserControl, IDynamicParameterControl
+   {
+      #region Properties
+
+      public NumericUpDown NumericUpDownControl { get { return numericUpDown1; } set { numericUpDown1 = value; } }
+      public string DescriptionText { get { return label1.Text; } set { label1.Text = value; } }
+      public string LabelText { get { return myLabel1.Text; } set { myLabel1.Text = value; } }
+      public TrackBar TrackBarControl { get { return trackBar1; } set { trackBar1 = value; } }
+      public int Scaler { get; set; }
+
+      #region Interface Properties
+
+      public string Value
+      {
+         get { return numericUpDown1.Value.ToString(CultureInfo.InvariantCulture); } 
+         set
+         {
+            numericUpDown1.Value = decimal.Parse(value);
+            numericUpDown1_ValueChanged(null, null);
+         }
+      }
+
+      #endregion
+
+      #endregion
+
+      #region Constructor
+
+      public RangeControl()
+      {
+         InitializeComponent();
+      }
+
+      #endregion
+
+      #region Methods
+
+      public void AttachEvents()
+      {
+         numericUpDown1.ValueChanged += numericUpDown1_ValueChanged;
+         trackBar1.ValueChanged += trackBar1_ValueChanged;
+      }
+
+      #endregion
+
+      #region Events
+
+      protected void numericUpDown1_ValueChanged(object sender, EventArgs e)
+      {
+         trackBar1.Value = (Scaler > 0) ? (int)(numericUpDown1.Value * Scaler) : (int)numericUpDown1.Value;
+      }
+
+      protected void trackBar1_ValueChanged(object sender, EventArgs e)
+      {
+         numericUpDown1.Value = (Scaler > 0) ? (trackBar1.Value / (decimal)Scaler) : trackBar1.Value;
+         numericUpDown1.Text = numericUpDown1.Value.ToString();
+      }
+
+      #endregion
+   }
+}
diff --git a/Tools/ArdupilotMegaPlanner/Controls/RangeControl.resx b/Tools/ArdupilotMegaPlanner/Controls/RangeControl.resx
new file mode 100644
index 000000000..7080a7d11
--- /dev/null
+++ b/Tools/ArdupilotMegaPlanner/Controls/RangeControl.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/Tools/ArdupilotMegaPlanner/Controls/ValuesControl.Designer.cs b/Tools/ArdupilotMegaPlanner/Controls/ValuesControl.Designer.cs
new file mode 100644
index 000000000..387d57a49
--- /dev/null
+++ b/Tools/ArdupilotMegaPlanner/Controls/ValuesControl.Designer.cs
@@ -0,0 +1,105 @@
+namespace ArdupilotMega.Controls
+{
+   partial class ValuesControl
+   {
+      /// <summary> 
+      /// Required designer variable.
+      /// </summary>
+      private System.ComponentModel.IContainer components = null;
+
+      /// <summary> 
+      /// Clean up any resources being used.
+      /// </summary>
+      /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+      protected override void Dispose(bool disposing)
+      {
+         if (disposing && (components != null))
+         {
+            components.Dispose();
+         }
+         base.Dispose(disposing);
+      }
+
+      #region Component Designer generated code
+
+      /// <summary> 
+      /// Required method for Designer support - do not modify 
+      /// the contents of this method with the code editor.
+      /// </summary>
+      private void InitializeComponent()
+      {
+         this.comboBox1 = new System.Windows.Forms.ComboBox();
+         this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
+         this.label1 = new System.Windows.Forms.Label();
+         this.myLabel1 = new ArdupilotMega.Controls.MyLabel();
+         this.tableLayoutPanel1.SuspendLayout();
+         this.SuspendLayout();
+         // 
+         // comboBox1
+         // 
+         this.comboBox1.FormattingEnabled = true;
+         this.comboBox1.Location = new System.Drawing.Point(3, 21);
+         this.comboBox1.Name = "comboBox1";
+         this.comboBox1.Size = new System.Drawing.Size(206, 21);
+         this.comboBox1.TabIndex = 1;
+         // 
+         // tableLayoutPanel1
+         // 
+         this.tableLayoutPanel1.AutoSize = true;
+         this.tableLayoutPanel1.ColumnCount = 1;
+         this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
+         this.tableLayoutPanel1.Controls.Add(this.comboBox1, 0, 1);
+         this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0);
+         this.tableLayoutPanel1.Location = new System.Drawing.Point(4, 28);
+         this.tableLayoutPanel1.Name = "tableLayoutPanel1";
+         this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(0, 5, 0, 10);
+         this.tableLayoutPanel1.RowCount = 2;
+         this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
+         this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
+         this.tableLayoutPanel1.Size = new System.Drawing.Size(471, 55);
+         this.tableLayoutPanel1.TabIndex = 2;
+         // 
+         // label1
+         // 
+         this.label1.AutoSize = true;
+         this.label1.Location = new System.Drawing.Point(3, 5);
+         this.label1.Name = "label1";
+         this.label1.Size = new System.Drawing.Size(35, 13);
+         this.label1.TabIndex = 0;
+         this.label1.Text = "label1";
+         // 
+         // myLabel1
+         // 
+         this.myLabel1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+         this.myLabel1.Location = new System.Drawing.Point(4, 3);
+         this.myLabel1.Name = "myLabel1";
+         this.myLabel1.resize = false;
+         this.myLabel1.Size = new System.Drawing.Size(206, 23);
+         this.myLabel1.TabIndex = 0;
+         this.myLabel1.Text = "myLabel1";
+         // 
+         // ValuesControl
+         // 
+         this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+         this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+         this.AutoSize = true;
+         this.Controls.Add(this.tableLayoutPanel1);
+         this.Controls.Add(this.myLabel1);
+         this.Name = "ValuesControl";
+         this.Size = new System.Drawing.Size(478, 108);
+         this.tableLayoutPanel1.ResumeLayout(false);
+         this.tableLayoutPanel1.PerformLayout();
+         this.ResumeLayout(false);
+         this.PerformLayout();
+
+      }
+
+      #endregion
+
+      private ArdupilotMega.Controls.MyLabel myLabel1;
+      private System.Windows.Forms.ComboBox comboBox1;
+      private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
+      private System.Windows.Forms.Label label1;
+
+   }
+}
diff --git a/Tools/ArdupilotMegaPlanner/Controls/ValuesControl.cs b/Tools/ArdupilotMegaPlanner/Controls/ValuesControl.cs
new file mode 100644
index 000000000..f3cfbb611
--- /dev/null
+++ b/Tools/ArdupilotMegaPlanner/Controls/ValuesControl.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace ArdupilotMega.Controls
+{
+   public partial class ValuesControl : UserControl, IDynamicParameterControl
+   {
+      #region Properties
+
+      public string LabelText { get { return myLabel1.Text; } set { myLabel1.Text = value; } }
+      public string DescriptionText { get { return label1.Text; } set { label1.Text = value; } }
+      public ComboBox ComboBoxControl { get { return comboBox1; } set { comboBox1 = value; } }
+
+      #region Interface Properties
+
+      public string Value { get { return comboBox1.SelectedValue.ToString(); } set { comboBox1.SelectedValue = value; } }
+
+      #endregion
+
+      #endregion
+
+      #region Constructor
+
+      public ValuesControl()
+      {
+         InitializeComponent();
+      }
+
+      #endregion
+   }
+}
diff --git a/Tools/ArdupilotMegaPlanner/Controls/ValuesControl.resx b/Tools/ArdupilotMegaPlanner/Controls/ValuesControl.resx
new file mode 100644
index 000000000..7080a7d11
--- /dev/null
+++ b/Tools/ArdupilotMegaPlanner/Controls/ValuesControl.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigFriendlyParams.Designer.cs b/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigFriendlyParams.Designer.cs
new file mode 100644
index 000000000..444a62e31
--- /dev/null
+++ b/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigFriendlyParams.Designer.cs
@@ -0,0 +1,93 @@
+namespace ArdupilotMega.GCSViews.ConfigurationView
+{
+   partial class ConfigFriendlyParams
+   {
+      /// <summary> 
+      /// Required designer variable.
+      /// </summary>
+      private System.ComponentModel.IContainer components = null;
+
+      /// <summary> 
+      /// Clean up any resources being used.
+      /// </summary>
+      /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+      protected override void Dispose(bool disposing)
+      {
+         if (disposing && (components != null))
+         {
+            components.Dispose();
+         }
+         base.Dispose(disposing);
+      }
+
+      #region Component Designer generated code
+
+      /// <summary> 
+      /// Required method for Designer support - do not modify 
+      /// the contents of this method with the code editor.
+      /// </summary>
+      private void InitializeComponent()
+      {
+         this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
+         this.BUT_rerequestparams = new ArdupilotMega.Controls.MyButton();
+         this.BUT_writePIDS = new ArdupilotMega.Controls.MyButton();
+         this.SuspendLayout();
+         // 
+         // tableLayoutPanel1
+         // 
+         this.tableLayoutPanel1.AutoScroll = true;
+         this.tableLayoutPanel1.ColumnCount = 1;
+         this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
+         this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
+         this.tableLayoutPanel1.Location = new System.Drawing.Point(12, 36);
+         this.tableLayoutPanel1.Name = "tableLayoutPanel1";
+         this.tableLayoutPanel1.RowCount = 1;
+         this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
+         this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 110F));
+         this.tableLayoutPanel1.Size = new System.Drawing.Size(514, 110);
+         this.tableLayoutPanel1.TabIndex = 0;
+         // 
+         // BUT_rerequestparams
+         // 
+         this.BUT_rerequestparams.ImeMode = System.Windows.Forms.ImeMode.NoControl;
+         this.BUT_rerequestparams.Location = new System.Drawing.Point(121, 11);
+         this.BUT_rerequestparams.Name = "BUT_rerequestparams";
+         this.BUT_rerequestparams.Padding = new System.Windows.Forms.Padding(0, 15, 0, 0);
+         this.BUT_rerequestparams.Size = new System.Drawing.Size(103, 19);
+         this.BUT_rerequestparams.TabIndex = 73;
+         this.BUT_rerequestparams.Text = "Refresh Params";
+         this.BUT_rerequestparams.UseVisualStyleBackColor = true;
+         // 
+         // BUT_writePIDS
+         // 
+         this.BUT_writePIDS.ImeMode = System.Windows.Forms.ImeMode.NoControl;
+         this.BUT_writePIDS.Location = new System.Drawing.Point(12, 11);
+         this.BUT_writePIDS.Name = "BUT_writePIDS";
+         this.BUT_writePIDS.Padding = new System.Windows.Forms.Padding(0, 15, 0, 0);
+         this.BUT_writePIDS.Size = new System.Drawing.Size(103, 19);
+         this.BUT_writePIDS.TabIndex = 74;
+         this.BUT_writePIDS.Text = "Write Params";
+         this.BUT_writePIDS.UseVisualStyleBackColor = true;
+         // 
+         // ConfigFriendlyParams
+         // 
+         this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+         this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+         this.AutoSize = true;
+         this.Controls.Add(this.BUT_rerequestparams);
+         this.Controls.Add(this.BUT_writePIDS);
+         this.Controls.Add(this.tableLayoutPanel1);
+         this.Name = "ConfigFriendlyParams";
+         this.Size = new System.Drawing.Size(673, 177);
+         this.Load += new System.EventHandler(this.ConfigRawParamsV2_Load);
+         this.ResumeLayout(false);
+
+      }
+
+      #endregion
+
+      private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
+      private Controls.MyButton BUT_rerequestparams;
+      private Controls.MyButton BUT_writePIDS;
+   }
+}
diff --git a/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigFriendlyParams.cs b/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigFriendlyParams.cs
new file mode 100644
index 000000000..372c8adcb
--- /dev/null
+++ b/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigFriendlyParams.cs
@@ -0,0 +1,382 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using ArdupilotMega.Controls;
+using ArdupilotMega.Controls.BackstageView;
+using ArdupilotMega.Utilities;
+using log4net;
+
+namespace ArdupilotMega.GCSViews.ConfigurationView
+{
+   public partial class ConfigFriendlyParams : BackStageViewContentPanel
+   {
+      #region Class Fields
+
+      private static readonly ILog log =
+        LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+      private readonly ParameterMetaDataRepository _parameterMetaDataRepository;
+      private Dictionary<string, string> _params = new Dictionary<string, string>();
+
+      #endregion
+
+      #region Properties
+
+      /// <summary>
+      /// Gets or sets the parameter mode.
+      /// </summary>
+      /// <value>
+      /// The parameter mode.
+      /// </value>
+      public string ParameterMode { get; set; }
+
+      #endregion
+
+      #region Constructor
+
+      public ConfigFriendlyParams()
+      {
+         InitializeComponent();
+         tableLayoutPanel1.Height = this.Height;
+         _parameterMetaDataRepository = new ParameterMetaDataRepository();
+
+         MainV2.comPort.ParamListChanged += comPort_ParamListChanged;
+         Resize += this_Resize;
+
+         BUT_rerequestparams.Click += BUT_rerequestparams_Click;
+         BUT_writePIDS.Click += BUT_writePIDS_Click;
+      }
+
+      #endregion
+
+      #region Events
+
+      /// <summary>
+      /// Handles the Click event of the BUT_writePIDS control.
+      /// </summary>
+      /// <param name="sender">The source of the event.</param>
+      /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
+      protected void BUT_writePIDS_Click(object sender, EventArgs e)
+      {
+         bool errorThrown = false;
+         _params.ForEach(x =>
+         {
+            var matchingControls = tableLayoutPanel1.Controls.Find(x.Key, true);
+            if(matchingControls.Length > 0)
+            {
+               var ctl = (IDynamicParameterControl)matchingControls[0];
+               try
+               {
+                  MainV2.comPort.setParam(x.Key, float.Parse(ctl.Value));
+               }
+               catch
+               {
+                  errorThrown = true;
+                  CustomMessageBox.Show("Set " + x.Key + " Failed");
+               }
+            }
+         });
+         if(!errorThrown)
+         {
+            CustomMessageBox.Show("Parameters successfully saved.");
+         }
+      }
+
+      /// <summary>
+      /// Handles the Click event of the BUT_rerequestparams control.
+      /// </summary>
+      /// <param name="sender">The source of the event.</param>
+      /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
+      protected void BUT_rerequestparams_Click(object sender, EventArgs e)
+      {
+         if (!MainV2.comPort.BaseStream.IsOpen)
+            return;
+
+         ((Control)sender).Enabled = false;
+
+         try
+         {
+            MainV2.comPort.getParamList();
+         }
+         catch (Exception ex)
+         {
+            log.Error("Exception getting param list", ex);
+            CustomMessageBox.Show("Error: getting param list");
+         }
+
+
+         ((Control)sender).Enabled = true;
+
+         BindParamList();
+      }
+
+      /// <summary>
+      /// Handles the Resize event of the this control.
+      /// </summary>
+      /// <param name="sender">The source of the event.</param>
+      /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
+      protected void this_Resize(object sender, EventArgs e)
+      {
+         tableLayoutPanel1.Height = this.Height - 50;
+      }
+
+      /// <summary>
+      /// Handles the Load event of the ConfigRawParamsV2 control.
+      /// </summary>
+      /// <param name="sender">The source of the event.</param>
+      /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
+      protected void ConfigRawParamsV2_Load(object sender, EventArgs e)
+      {
+         BindParamList();
+      }
+
+      /// <summary>
+      /// Handles the ParamListChanged event of the comPort control.
+      /// </summary>
+      /// <param name="sender">The source of the event.</param>
+      /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
+      protected void comPort_ParamListChanged(object sender, EventArgs e)
+      {
+         SortParamList();
+      }
+
+      #endregion
+
+      #region Methods
+
+      /// <summary>
+      /// Loads the param file.
+      /// </summary>
+      /// <param name="Filename">The filename.</param>
+      /// <returns></returns>
+      private Hashtable loadParamFile(string Filename)
+      {
+         Hashtable param = new Hashtable();
+
+         StreamReader sr = new StreamReader(Filename);
+         while (!sr.EndOfStream)
+         {
+            string line = sr.ReadLine();
+
+            if (line.Contains("NOTE:"))
+               CustomMessageBox.Show(line, "Saved Note");
+
+            if (line.StartsWith("#"))
+               continue;
+
+            string[] items = line.Split(new char[] { ' ', ',', '\t' }, StringSplitOptions.RemoveEmptyEntries);
+
+            if (items.Length != 2)
+               continue;
+
+            string name = items[0];
+            float value = float.Parse(items[1], new System.Globalization.CultureInfo("en-US"));
+
+            MAVLink.modifyParamForDisplay(true, name, ref value);
+
+            if (name == "SYSID_SW_MREV")
+               continue;
+            if (name == "WP_TOTAL")
+               continue;
+            if (name == "CMD_TOTAL")
+               continue;
+            if (name == "FENCE_TOTAL")
+               continue;
+            if (name == "SYS_NUM_RESETS")
+               continue;
+            if (name == "ARSPD_OFFSET")
+               continue;
+            if (name == "GND_ABS_PRESS")
+               continue;
+            if (name == "GND_TEMP")
+               continue;
+            if (name == "CMD_INDEX")
+               continue;
+            if (name == "LOG_LASTFILE")
+               continue;
+
+            param[name] = value;
+         }
+         sr.Close();
+
+         return param;
+      }
+
+      /// <summary>
+      /// Sorts the param list.
+      /// </summary>
+      private void SortParamList()
+      {
+         // Clear list
+         _params.Clear();
+
+         // When the parameter list is changed, re sort the list for our View's purposes
+         MainV2.comPort.param.Keys.ForEach(x => 
+         {
+            string displayName = _parameterMetaDataRepository.GetParameterMetaData(x.ToString(), ParameterMetaDataConstants.DisplayName);
+            string parameterMode = _parameterMetaDataRepository.GetParameterMetaData(x.ToString(), ParameterMetaDataConstants.User);
+            
+            // If we have a friendly display name AND
+            if (!String.IsNullOrEmpty(displayName) && 
+                  // The user type is equal to the ParameterMode specified at class instantiation OR
+                  ((!String.IsNullOrEmpty(parameterMode) && parameterMode == ParameterMode) || 
+                  // The user type is empty and this is in Advanced mode
+                  String.IsNullOrEmpty(parameterMode) && ParameterMode == ParameterMetaDataConstants.Advanced))
+            {
+               _params.Add(x.ToString(), displayName);
+            }
+         });
+         _params = _params.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
+      }
+
+      /// <summary>
+      /// Binds the param list.
+      /// </summary>
+      private void BindParamList()
+      {
+         tableLayoutPanel1.Controls.Clear();
+         if (_params == null || _params.Count == 0) SortParamList();
+         _params.ForEach(x => 
+         {
+            if(!String.IsNullOrEmpty(x.Key))
+            {
+               bool controlAdded = false;
+
+               string value = ((float)MainV2.comPort.param[x.Key]).ToString("0.###");
+               string description = _parameterMetaDataRepository.GetParameterMetaData(x.Key, ParameterMetaDataConstants.Description);
+               string displayName = x.Value;
+               string units = _parameterMetaDataRepository.GetParameterMetaData(x.Key, ParameterMetaDataConstants.Units);
+                  
+               // If this is a range
+               string rangeRaw = _parameterMetaDataRepository.GetParameterMetaData(x.Key, ParameterMetaDataConstants.Range);
+               string incrementRaw = _parameterMetaDataRepository.GetParameterMetaData(x.Key, ParameterMetaDataConstants.Increment);
+               if (!String.IsNullOrEmpty(rangeRaw) && !String.IsNullOrEmpty(incrementRaw))
+               {
+                  float increment, intValue;
+                  float.TryParse(incrementRaw, out increment);
+                  float.TryParse(value, out intValue);
+
+                  string[] rangeParts = rangeRaw.Split(new[] { ' ' });
+                  if (rangeParts.Count() == 2 && increment > 0)
+                  {
+                     float lowerRange;
+                     float.TryParse(rangeParts[0], out lowerRange);
+                     float upperRange;
+                     float.TryParse(rangeParts[1], out upperRange);
+
+                     int scaler = Int32.Parse((1/increment).ToString(CultureInfo.InvariantCulture));
+                     int scaledLowerRange = 0, scaledUpperRange = 0;
+                     int scaledIncrement = (int)increment;
+                     if(scaler > 0)
+                     {
+                        scaledLowerRange = (int)(lowerRange * scaler);
+                        scaledUpperRange = (int)(upperRange * scaler);
+                        scaledIncrement = Int32.Parse((increment * scaler).ToString(CultureInfo.InvariantCulture));
+                        intValue *= scaler;
+                     }
+
+                     var rangeControl = new RangeControl();
+                     rangeControl.Name = x.Key;
+                     rangeControl.Scaler = scaler;
+                     rangeControl.DescriptionText = FitDescriptionText(units, description);
+                     rangeControl.LabelText = displayName;
+                     rangeControl.TrackBarControl.Minimum = scaledLowerRange;
+                     rangeControl.TrackBarControl.Maximum = scaledUpperRange;
+                     rangeControl.TrackBarControl.TickFrequency = scaledIncrement;
+                     rangeControl.TrackBarControl.Value = (int)intValue;
+
+                     rangeControl.NumericUpDownControl.Increment = (decimal)increment;
+                     rangeControl.NumericUpDownControl.DecimalPlaces = scaler.ToString(CultureInfo.InvariantCulture).Length - 1;
+                     rangeControl.NumericUpDownControl.Minimum = (decimal) lowerRange;
+                     rangeControl.NumericUpDownControl.Maximum = (decimal)upperRange;
+                     rangeControl.NumericUpDownControl.Value = (decimal)((float)MainV2.comPort.param[x.Key]);
+
+                     rangeControl.AttachEvents();
+
+                     tableLayoutPanel1.Controls.Add(rangeControl);
+
+                     controlAdded = true;
+                  }
+               }
+
+               if (!controlAdded)
+               {
+                  // If this is a subset of values
+                  string availableValuesRaw = _parameterMetaDataRepository.GetParameterMetaData(x.Key, ParameterMetaDataConstants.Values);
+                  if (!String.IsNullOrEmpty(availableValuesRaw))
+                  {
+                     string[] availableValues = availableValuesRaw.Split(new[] { ',' });
+                     if (availableValues.Any())
+                     {
+                        var valueControl = new ValuesControl();
+                        valueControl.Name = x.Key;
+                        valueControl.DescriptionText = FitDescriptionText(units, description);
+                        valueControl.LabelText = displayName;
+
+                        var splitValues = new List<KeyValuePair<string, string>>();
+                        // Add the values to the ddl
+                        availableValues.ForEach(val =>
+                        {
+                           string[] valParts = val.Split(new[]{ ':' });
+                           splitValues.Add(new KeyValuePair<string, string>(valParts[0], (valParts.Length > 1) ? valParts[1] : valParts[0]));
+                        });
+                        valueControl.ComboBoxControl.DisplayMember = "Value";
+                        valueControl.ComboBoxControl.ValueMember = "Key";
+                        valueControl.ComboBoxControl.DataSource = splitValues;
+                        valueControl.ComboBoxControl.SelectedValue = value;
+
+                        tableLayoutPanel1.Controls.Add(valueControl);
+                     }
+                  }
+               }
+            }
+         });
+      }
+
+      /// <summary>
+      /// Fits the description text.
+      /// </summary>
+      /// <param name="description">The description.</param>
+      /// <returns></returns>
+      private string FitDescriptionText(string description)
+      {
+         return FitDescriptionText(string.Empty, description);
+      }
+
+      /// <summary>
+      /// Fits the description text.
+      /// </summary>
+      /// <param name="units">The units.</param>
+      /// <param name="description">The description.</param>
+      /// <returns></returns>
+      private string FitDescriptionText(string units, string description)
+      {
+         var returnDescription = new StringBuilder();
+         
+         if(!String.IsNullOrEmpty(units))
+         {
+            returnDescription.Append(String.Format("Units: {0}{1}", units, Environment.NewLine));
+         }
+
+         if(!String.IsNullOrEmpty(description))
+         {
+            returnDescription.Append("Description: ");
+            var descriptionParts = description.Split(new char[] {' '});
+            for(int i = 0; i < descriptionParts.Length; i++)
+            {
+               returnDescription.Append(String.Format("{0} ", descriptionParts[i]));
+               if (i != 0 && i % 10 == 0) returnDescription.Append(Environment.NewLine);
+            }
+         }
+
+         return returnDescription.ToString();
+      }
+
+      #endregion
+   }
+}
diff --git a/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigFriendlyParams.resx b/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigFriendlyParams.resx
new file mode 100644
index 000000000..7080a7d11
--- /dev/null
+++ b/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigFriendlyParams.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/Setup.cs b/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/Setup.cs
index 29cabc91f..9c49014dc 100644
--- a/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/Setup.cs
+++ b/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/Setup.cs
@@ -7,6 +7,7 @@ using System.Linq;
 using System.Text;
 using System.Windows.Forms;
 using ArdupilotMega.Controls.BackstageView;
+using ArdupilotMega.Utilities;
 
 namespace ArdupilotMega.GCSViews.ConfigurationView
 {
@@ -55,7 +56,9 @@ namespace ArdupilotMega.GCSViews.ConfigurationView
                     this.backstageView.AddPage(new BackstageView.BackstageViewPage(new ConfigArduplane(), "ArduPlane Config"));
                 }
 
-                this.backstageView.AddPage(new BackstageView.BackstageViewPage(new ConfigRawParams(), "Raw params (Adv)"));
+                this.backstageView.AddPage(new BackstageView.BackstageViewPage(new ConfigFriendlyParams { ParameterMode = ParameterMetaDataConstants.Standard }, "Standard Params"));
+                this.backstageView.AddPage(new BackstageView.BackstageViewPage(new ConfigFriendlyParams { ParameterMode = ParameterMetaDataConstants.Advanced }, "Advanced Params"));
+                this.backstageView.AddPage(new BackstageView.BackstageViewPage(new ConfigRawParams(), "Parameter List"));
             }
 
             
diff --git a/Tools/ArdupilotMegaPlanner/MAVLink.cs b/Tools/ArdupilotMegaPlanner/MAVLink.cs
index cdf63dbd2..fb35e00aa 100644
--- a/Tools/ArdupilotMegaPlanner/MAVLink.cs
+++ b/Tools/ArdupilotMegaPlanner/MAVLink.cs
@@ -21,6 +21,7 @@ namespace ArdupilotMega
     {
         private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
         public ICommsSerial BaseStream = new SerialPort();
+        public event EventHandler ParamListChanged;
 
         private const double CONNECT_TIMEOUT_SECONDS = 30;
 
@@ -569,6 +570,7 @@ namespace ArdupilotMega
 
         }
         */
+
         public void getParamList()
         {
             frmProgressReporter = new ProgressReporterDialogue
@@ -582,6 +584,11 @@ namespace ArdupilotMega
             ThemeManager.ApplyThemeTo(frmProgressReporter);
 
             frmProgressReporter.RunBackgroundOperationAsync();
+
+            if (ParamListChanged != null)
+            {
+               ParamListChanged(this, null);
+            }
         }
 
         void FrmProgressReporterGetParams(object sender, ProgressWorkerEventArgs e)
diff --git a/Tools/ArdupilotMegaPlanner/MainV2.cs b/Tools/ArdupilotMegaPlanner/MainV2.cs
index 92f48399b..5b6dcb93c 100644
--- a/Tools/ArdupilotMegaPlanner/MainV2.cs
+++ b/Tools/ArdupilotMegaPlanner/MainV2.cs
@@ -15,7 +15,7 @@ using System.Runtime.InteropServices;
 using System.Speech.Synthesis;
 using System.Globalization;
 using System.Threading;
-using System.Net.Sockets;
+using System.Net.Sockets;
 using ArdupilotMega.Utilities;
 using IronPython.Hosting;
 using log4net;
@@ -1207,21 +1207,13 @@ namespace ArdupilotMega
                 Name = "Main Serial reader"
             }.Start();
 
-            // check for updates
-            if (Debugger.IsAttached)
+            try
             {
-                log.Info("Skipping update test as it appears we are debugging");
+               CheckForUpdate();
             }
-            else
+            catch (Exception ex)
             {
-                try
-                {
-                    CheckForUpdate();
-                }
-                catch (Exception ex)
-                {
-                    log.Error("Update check failed", ex);
-                }
+               log.Error("Update check failed", ex);
             }
         }
 
@@ -1741,7 +1733,16 @@ namespace ArdupilotMega
            #endregion Fetch Parameter Meta Data
 
            progressReporterDialogue.UpdateProgressAndStatus(-1, "Getting Base URL");
-           MainV2.updateCheckMain(progressReporterDialogue);
+
+           // check for updates
+           if (Debugger.IsAttached)
+           {
+              log.Info("Skipping update test as it appears we are debugging");
+           }
+           else
+           {
+              MainV2.updateCheckMain(progressReporterDialogue);
+           }
         }
 
         private static bool updateCheck(ProgressReporterDialogue frmProgressReporter, string baseurl, string subdir)
diff --git a/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataConstants.cs b/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataConstants.cs
index fb29584b0..64d6d3c83 100644
--- a/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataConstants.cs
+++ b/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataConstants.cs
@@ -18,6 +18,16 @@
       public const string Description = "Description";
       public const string Units = "Units";
       public const string Range = "Range";
+      public const string Values = "Values";
+      public const string Increment = "Increment";
+      public const string User = "User";
+
+      #endregion
+
+      #region Meta Values
+
+      public const string Advanced = "Advanced";
+      public const string Standard = "Standard";
 
       #endregion
    }
-- 
GitLab