diff --git a/Tools/ArdupilotMegaPlanner/ArduCopterConfig.xml b/Tools/ArdupilotMegaPlanner/ArduCopterConfig.xml index 2558e46e2c..fda38f6780 100644 --- a/Tools/ArdupilotMegaPlanner/ArduCopterConfig.xml +++ b/Tools/ArdupilotMegaPlanner/ArduCopterConfig.xml @@ -101,6 +101,70 @@ Too high = slow wobbles 0.001 + + Yaw Angular Rate Control: + How much throttle is applied to rotate the copter at the desired speed. + + + + P + RATE_YAW_P + 0.001 + 5 + 0.001 + + + I + RATE_YAW_I + 0 + 5 + 0.001 + + + D + RATE_YAW_D + 0 + 5 + 0.001 + + + IMAX + RATE_YAW_IMAX + 0 + 50 + 1 + + + + Yaw Stabilize Control: + + How fast the copter reacts to user or autopilot input. + Higher = more aggressive control. + Too high = slow wobbles + + + + P + STB_YAW_P + 0.001 + 10 + 0.001 + + + I + STB_YAW_I + 0 + 5 + 0.001 + + + IMAX + STB_YAW_IMAX + 0 + 50 + 1 + + @@ -140,7 +204,7 @@ How much angle is applied to make the copter accelerate to the desired speed. LOITER_LON_IMAX 0 50 - 0.1 + 1 Loiter Speed: diff --git a/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj b/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj index def4fc453c..b318087f83 100644 --- a/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj +++ b/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj @@ -226,6 +226,7 @@ + UserControl diff --git a/Tools/ArdupilotMegaPlanner/MainV2.cs b/Tools/ArdupilotMegaPlanner/MainV2.cs index f04826220b..907bb8c6ca 100644 --- a/Tools/ArdupilotMegaPlanner/MainV2.cs +++ b/Tools/ArdupilotMegaPlanner/MainV2.cs @@ -1733,8 +1733,18 @@ namespace ArdupilotMega static void DoUpdateWorker_DoWork(object sender, Controls.ProgressWorkerEventArgs e) { - ((ProgressReporterDialogue)sender).UpdateProgressAndStatus(-1, "Getting Base URL"); - MainV2.updateCheckMain((ProgressReporterDialogue)sender); + // TODO: Is this the right place? + #region Fetch Parameter Meta Data + + var progressReporterDialogue = ((ProgressReporterDialogue) sender); + progressReporterDialogue.UpdateProgressAndStatus(-1, "Getting Updated Parameters"); + + ParameterMetaDataParser.GetParameterInformation(); + + #endregion Fetch Parameter Meta Data + + progressReporterDialogue.UpdateProgressAndStatus(-1, "Getting Base URL"); + MainV2.updateCheckMain(progressReporterDialogue); } private static bool updateCheck(ProgressReporterDialogue frmProgressReporter, string baseurl, string subdir) diff --git a/Tools/ArdupilotMegaPlanner/Msi/wix.pdb b/Tools/ArdupilotMegaPlanner/Msi/wix.pdb index e2bd4a8c51..a5d4591677 100644 Binary files a/Tools/ArdupilotMegaPlanner/Msi/wix.pdb and b/Tools/ArdupilotMegaPlanner/Msi/wix.pdb differ diff --git a/Tools/ArdupilotMegaPlanner/Utilities/CollectionExtensions.cs b/Tools/ArdupilotMegaPlanner/Utilities/CollectionExtensions.cs new file mode 100644 index 0000000000..6b435af402 --- /dev/null +++ b/Tools/ArdupilotMegaPlanner/Utilities/CollectionExtensions.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ArdupilotMega.Utilities +{ + public static class CollectionExtensions + { + /// + /// Performs the specified on each element of the . + /// + /// + /// An enumerable instance. + /// + public static void ForEach(this IEnumerable enumerable, Action action) + { + foreach (object obj in enumerable) + action(obj); + } + + /// + /// Performs the specified on each element of the . + /// + /// + /// An enumerable instance. + /// + public static void ForEach(this IEnumerable enumerable, Action action) + { + foreach (T obj in enumerable) + action(obj); + } + + /// + /// Performs the specified on each element of the . + /// + /// + /// The type contained in the . + /// + public static void ForEach(this IEnumerable enumerable, Action action) + { + foreach (T obj in enumerable) + action(obj); + } + } +} diff --git a/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataConstants.cs b/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataConstants.cs index 7f189aa066..fb29584b08 100644 --- a/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataConstants.cs +++ b/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataConstants.cs @@ -2,11 +2,23 @@ { public sealed class ParameterMetaDataConstants { - public const string Delimeter = "@"; + #region Markers + + public const string ParamDelimeter = "@"; + public const string PathDelimeter = ","; public const string Param = "Param"; + public const string Group = "Group"; + public const string Path = "Path"; + + #endregion + + #region Meta Keys + public const string DisplayName = "DisplayName"; public const string Description = "Description"; public const string Units = "Units"; public const string Range = "Range"; + + #endregion } -} +} \ No newline at end of file diff --git a/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataParser.cs b/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataParser.cs index 2c3d2c0e13..d4498f0f5f 100644 --- a/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataParser.cs +++ b/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataParser.cs @@ -7,13 +7,15 @@ using System.Net; using System.Text.RegularExpressions; using System.Windows.Forms; using System.Xml; +using ArdupilotMega.Utilities; using log4net; namespace ArdupilotMega.Utilities { public static class ParameterMetaDataParser { - private static readonly Regex _paramMetaRegex = new Regex(String.Format("{0}(?[^:]+):(?.+)", ParameterMetaDataConstants.Delimeter)); + private static readonly Regex _paramMetaRegex = new Regex(String.Format("{0}(?[^:]+):(?.+)", ParameterMetaDataConstants.ParamDelimeter)); + private static readonly Regex _parentDirectoryRegex = new Regex("(?[../]*)(?.+)"); private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); @@ -34,51 +36,16 @@ namespace ArdupilotMega.Utilities foreach (string parameterLocation in parameterLocations) { - log.Info(parameterLocation); + // Write the start element for this parameter location + objXmlTextWriter.WriteStartElement(parameterLocation.ToLower().Contains("arducopter") ? MainV2.Firmwares.ArduCopter2.ToString() : MainV2.Firmwares.ArduPlane.ToString()); - var request = WebRequest.Create(parameterLocation); + // Read and parse the content. + string dataFromAddress = ReadDataFromAddress(parameterLocation); + ParseGroupInformation(dataFromAddress, objXmlTextWriter, parameterLocation); + ParseParameterInformation(dataFromAddress, objXmlTextWriter); - // Plenty of timeout - request.Timeout = 10000; - - // Set the Method property of the request to GET. - request.Method = "GET"; - - // Get the response. - using (var response = request.GetResponse()) - { - // Display the status. - log.Info(((HttpWebResponse)response).StatusDescription); - - // Get the stream containing content returned by the server. - using (var dataStream = response.GetResponseStream()) - { - if (dataStream != null) - { - // Open the stream using a StreamReader for easy access. - using (var reader = new StreamReader(dataStream)) - { - // Write the start element for this parameter location - objXmlTextWriter.WriteStartElement(parameterLocation); - - // Read and parse the content. - ParseParameterInformation(reader.ReadToEnd(), objXmlTextWriter); - - // Write the end element for this parameter location - objXmlTextWriter.WriteEndElement(); - - // Close the reader - reader.Close(); - } - - // Close the datastream - dataStream.Close(); - } - } - - // Close the response - response.Close(); - } + // Write the end element for this parameter location + objXmlTextWriter.WriteEndElement(); } @@ -90,6 +57,67 @@ namespace ArdupilotMega.Utilities } } + /// + /// Parses the group parameter information. + /// + /// The file contents. + /// The obj XML text writer. + /// The parameter location. + private static void ParseGroupInformation(string fileContents, XmlTextWriter objXmlTextWriter, string parameterLocation) + { + var parsedInformation = ParseKeyValuePairs(fileContents, ParameterMetaDataConstants.Group); + if (parsedInformation != null && parsedInformation.Count > 0) + { + // node is the prefix of the parameter group here + parsedInformation.ForEach(node => + { + // node.Value is a nested dictionary containing the additional meta data + // In this case we are looking for the @Path key + if (node.Value != null && node.Value.Count > 0) + { + // Find the @Path key + node.Value + .Where(meta => meta.Key == ParameterMetaDataConstants.Path) + // We might have multiple paths to inspect, so break them out by the delimeter + .ForEach(path => path.Value.Split(new []{ ParameterMetaDataConstants.PathDelimeter }, StringSplitOptions.None) + .ForEach(separatedPath => + { + // Match based on the regex defined at the top of this class + Match pathMatch = _parentDirectoryRegex.Match(separatedPath); + if (pathMatch.Success && pathMatch.Groups["Path"] != null && !String.IsNullOrEmpty(pathMatch.Groups["Path"].Value)) + { + if (pathMatch.Groups["ParentDirectory"] != null && !String.IsNullOrEmpty(pathMatch.Groups["ParentDirectory"].Value)) + { + // How many directories from the original path do we have to move + int numberOfParentDirectoryMoves = pathMatch.Groups["ParentDirectory"].Value.Split(new string[] { "../" }, StringSplitOptions.None).Count(); + + // We need to remove the http:// or https:// prefix to build the new URL properly + string httpTest = parameterLocation.Substring(0, 7); + int trimHttpPrefixIdx = httpTest == "http://" ? 7 : 8; + + // Get the parts of the original URL + var parameterLocationParts = parameterLocation.Substring(trimHttpPrefixIdx, parameterLocation.Length - trimHttpPrefixIdx).Split(new char[] { '/' }); + + // Rebuild the new url taking into account the numberOfParentDirectoryMoves + string urlAfterParentDirectory = string.Empty; + for (int i = 0; i < parameterLocationParts.Length && i < parameterLocationParts.Length - numberOfParentDirectoryMoves; i++) + { + urlAfterParentDirectory += parameterLocationParts[i] + "/"; + } + + // This is the URL of the file we need to parse for comments + string newPath = String.Format("{0}{1}{2}", parameterLocation.Substring(0, trimHttpPrefixIdx), urlAfterParentDirectory, pathMatch.Groups["Path"].Value); + + // Parse the param info from the newly constructed URL + ParseParameterInformation(ReadDataFromAddress(newPath), objXmlTextWriter, node.Key); + } + } + })); + } + }); + } + } + /// /// Parses the parameter information. /// @@ -97,8 +125,50 @@ namespace ArdupilotMega.Utilities /// The obj XML text writer. private static void ParseParameterInformation(string fileContents, XmlTextWriter objXmlTextWriter) { + ParseParameterInformation(fileContents, objXmlTextWriter, string.Empty); + } + + /// + /// Parses the parameter information. + /// + /// The file contents. + /// The obj XML text writer. + /// The parameter prefix. + private static void ParseParameterInformation(string fileContents, XmlTextWriter objXmlTextWriter, string parameterPrefix) + { + var parsedInformation = ParseKeyValuePairs(fileContents, ParameterMetaDataConstants.Param); + if(parsedInformation != null && parsedInformation.Count > 0) + { + parsedInformation.ForEach(node => + { + objXmlTextWriter.WriteStartElement(String.Format("{0}{1}", parameterPrefix, node.Key)); + if (node.Value != null && node.Value.Count > 0) + { + node.Value.ForEach(meta => + { + // Write the key value pair to XML + objXmlTextWriter.WriteStartElement(meta.Key); + objXmlTextWriter.WriteString(meta.Value); + objXmlTextWriter.WriteEndElement(); + }); + } + objXmlTextWriter.WriteEndElement(); + }); + } + } + + /// + /// Parses the parameter information. + /// + /// The file contents. + /// The node key. + /// + private static Dictionary> ParseKeyValuePairs(string fileContents, string nodeKey) + { + var returnDict = new Dictionary>(); + var indicies = new List(); - GetIndexOfMarkers(ref indicies, fileContents, ParameterMetaDataConstants.Delimeter + ParameterMetaDataConstants.Param, 0); + GetIndexOfMarkers(ref indicies, fileContents, ParameterMetaDataConstants.ParamDelimeter + nodeKey, 0); if(indicies.Count > 0) { @@ -113,7 +183,7 @@ namespace ArdupilotMega.Utilities if(!String.IsNullOrEmpty(subStringToSearch)) { var metaIndicies = new List(); - GetIndexOfMarkers(ref metaIndicies, subStringToSearch, ParameterMetaDataConstants.Delimeter, 0); + GetIndexOfMarkers(ref metaIndicies, subStringToSearch, ParameterMetaDataConstants.ParamDelimeter, 0); if(metaIndicies.Count > 0) { @@ -123,40 +193,43 @@ namespace ArdupilotMega.Utilities // Match based on the regex defined at the top of this class Match paramNameKeyMatch = _paramMetaRegex.Match(paramNameKey); - if (paramNameKeyMatch.Success && paramNameKeyMatch.Groups["MetaKey"].Value == ParameterMetaDataConstants.Param) + if (paramNameKeyMatch.Success && paramNameKeyMatch.Groups["MetaKey"].Value == nodeKey) { - objXmlTextWriter.WriteStartElement(paramNameKeyMatch.Groups["MetaValue"].Value.Trim(new char[] { ' ' })); - - // Loop through the indicies of the meta data found - for (int x = 1; x < metaIndicies.Count; x++) + string key = paramNameKeyMatch.Groups["MetaValue"].Value.Trim(new char[] {' '}); + var metaDict = new Dictionary(); + if(!returnDict.ContainsKey(key)) { - // This is the end index for a substring to search for parameter attributes - // If we are on the last index in our collection, we will search to the end of the file - var stopMetaIdx = (x == metaIndicies.Count - 1) ? subStringToSearch.Length : metaIndicies[x + 1]; - - // This meta param string - var metaString = subStringToSearch.Substring(metaIndicies[x], (stopMetaIdx - metaIndicies[x])); - - // Match based on the regex defined at the top of this class - Match metaMatch = _paramMetaRegex.Match(metaString); - - // Test for success - if (metaMatch.Success) + // Loop through the indicies of the meta data found + for (int x = 1; x < metaIndicies.Count; x++) { - // Write the key value pair to XML - objXmlTextWriter.WriteStartElement(metaMatch.Groups["MetaKey"].Value.Trim(new char[] { ' ' })); - objXmlTextWriter.WriteString(metaMatch.Groups["MetaValue"].Value.Trim(new char[] { ' ' })); - objXmlTextWriter.WriteEndElement(); + // This is the end index for a substring to search for parameter attributes + // If we are on the last index in our collection, we will search to the end of the file + var stopMetaIdx = (x == metaIndicies.Count - 1) ? subStringToSearch.Length : metaIndicies[x + 1]; + + // This meta param string + var metaString = subStringToSearch.Substring(metaIndicies[x], (stopMetaIdx - metaIndicies[x])); + + // Match based on the regex defined at the top of this class + Match metaMatch = _paramMetaRegex.Match(metaString); + + // Test for success + if (metaMatch.Success) + { + string metaKey = metaMatch.Groups["MetaKey"].Value.Trim(new char[] {' '}); + if(!metaDict.ContainsKey(metaKey)) + { + metaDict.Add(metaKey, metaMatch.Groups["MetaValue"].Value.Trim(new char[] { ' ' })); + } + } } } - - // End this parameter node - objXmlTextWriter.WriteEndElement(); + returnDict.Add(key, metaDict); } } } } } + return returnDict; } /// @@ -188,5 +261,67 @@ namespace ArdupilotMega.Utilities } } } + + /// + /// Reads the data from address. + /// + /// The address. + /// + private static string ReadDataFromAddress(string address) + { + string data = string.Empty; + + log.Info(address); + + // Make sure we don't blow up if the user is not connected or the endpoint is not available + try + { + var request = WebRequest.Create(address); + + // Plenty of timeout + request.Timeout = 10000; + + // Set the Method property of the request to GET. + request.Method = "GET"; + + // Get the response. + using (var response = request.GetResponse()) + { + // Display the status. + log.Info(((HttpWebResponse)response).StatusDescription); + + // Get the stream containing content returned by the server. + using (var dataStream = response.GetResponseStream()) + { + if (dataStream != null) + { + // Open the stream using a StreamReader for easy access. + using (var reader = new StreamReader(dataStream)) + { + // Store the data to return + data = reader.ReadToEnd(); + + // Close the reader + reader.Close(); + } + + // Close the datastream + dataStream.Close(); + } + } + + // Close the response + response.Close(); + } + + // Return the data + return data; + } + catch (WebException ex) + { + log.Error(String.Format("The request to {0} failed.", address), ex); + } + return string.Empty; + } } } diff --git a/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataRepository.cs b/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataRepository.cs index 0697a76c07..738e684880 100644 --- a/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataRepository.cs +++ b/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataRepository.cs @@ -3,6 +3,7 @@ using System.Configuration; using System.IO; using System.Windows.Forms; using System.Xml.Linq; +using System.Linq; namespace ArdupilotMega.Utilities { @@ -32,7 +33,19 @@ namespace ArdupilotMega.Utilities { // Use this to find the endpoint node we are looking for // Either it will be pulled from a file in the ArduPlane hierarchy or the ArduCopter hierarchy - string endpointSearchString = (MainV2.cs.firmware == MainV2.Firmwares.ArduPlane) ? "arduplane" : "arducopter"; + var element = _parameterMetaDataXML.Element(MainV2.cs.firmware.ToString()); + if(element != null && element.HasElements) + { + var node = element.Element(nodeKey); + if(node != null && node.HasElements) + { + var metaValue = node.Element(metaKey); + if(metaValue != null) + { + return metaValue.Value; + } + } + } } return string.Empty; } diff --git a/Tools/ArdupilotMegaPlanner/app.config b/Tools/ArdupilotMegaPlanner/app.config index 063dfdef78..9bb4229ef3 100644 --- a/Tools/ArdupilotMegaPlanner/app.config +++ b/Tools/ArdupilotMegaPlanner/app.config @@ -8,6 +8,10 @@ + + diff --git a/Tools/ArdupilotMegaPlanner/bin/Release/ArduCopterConfig.xml b/Tools/ArdupilotMegaPlanner/bin/Release/ArduCopterConfig.xml index 2558e46e2c..fda38f6780 100644 --- a/Tools/ArdupilotMegaPlanner/bin/Release/ArduCopterConfig.xml +++ b/Tools/ArdupilotMegaPlanner/bin/Release/ArduCopterConfig.xml @@ -101,6 +101,70 @@ Too high = slow wobbles 0.001 + + Yaw Angular Rate Control: + How much throttle is applied to rotate the copter at the desired speed. + + + + P + RATE_YAW_P + 0.001 + 5 + 0.001 + + + I + RATE_YAW_I + 0 + 5 + 0.001 + + + D + RATE_YAW_D + 0 + 5 + 0.001 + + + IMAX + RATE_YAW_IMAX + 0 + 50 + 1 + + + + Yaw Stabilize Control: + + How fast the copter reacts to user or autopilot input. + Higher = more aggressive control. + Too high = slow wobbles + + + + P + STB_YAW_P + 0.001 + 10 + 0.001 + + + I + STB_YAW_I + 0 + 5 + 0.001 + + + IMAX + STB_YAW_IMAX + 0 + 50 + 1 + + @@ -140,7 +204,7 @@ How much angle is applied to make the copter accelerate to the desired speed. LOITER_LON_IMAX 0 50 - 0.1 + 1 Loiter Speed: diff --git a/Tools/ArdupilotMegaPlanner/bin/Release/version.txt b/Tools/ArdupilotMegaPlanner/bin/Release/version.txt index cf279dbac7..b68b098b7a 100644 --- a/Tools/ArdupilotMegaPlanner/bin/Release/version.txt +++ b/Tools/ArdupilotMegaPlanner/bin/Release/version.txt @@ -1 +1 @@ -1.1.4498.32482 \ No newline at end of file +1.1.4499.14296 \ No newline at end of file