diff --git a/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj b/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj index 1e1da84698..b59c4d3ae9 100644 --- a/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj +++ b/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj @@ -226,7 +226,8 @@ - + + UserControl diff --git a/Tools/ArdupilotMegaPlanner/Constants/ParameterMetaDataConstants.cs b/Tools/ArdupilotMegaPlanner/Constants/ParameterMetaDataConstants.cs deleted file mode 100644 index 73a226920b..0000000000 --- a/Tools/ArdupilotMegaPlanner/Constants/ParameterMetaDataConstants.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace ArdupilotMega.Constants -{ - public sealed class ParameterMetaDataConstants - { - public const string Delimeter = "@"; - public const string Param = "Param"; - public const string DisplayName = "DisplayName"; - public const string Description = "Description"; - public const string Units = "Units"; - public const string Range = "Range"; - } -} diff --git a/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigRawParams.cs b/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigRawParams.cs index 2ee33bf48a..e49bf42a85 100644 --- a/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigRawParams.cs +++ b/Tools/ArdupilotMegaPlanner/GCSViews/ConfigurationView/ConfigRawParams.cs @@ -1,20 +1,14 @@ using System; using System.Collections; -using System.Collections.Generic; using System.ComponentModel; -using System.Configuration; using System.Drawing; -using System.Data; using System.IO; -using System.Linq; using System.Text; -using System.Xml.Linq; using System.Windows.Forms; -using ArdupilotMega.Constants; using ArdupilotMega.Utilities; +using ArdupilotMega.Utilities.Constants; using log4net; using ArdupilotMega.Controls.BackstageView; -using ArdupilotMega.Controls; namespace ArdupilotMega.GCSViews.ConfigurationView { 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/Constants/ParameterMetaDataConstants.cs b/Tools/ArdupilotMegaPlanner/Utilities/Constants/ParameterMetaDataConstants.cs new file mode 100644 index 0000000000..b8764f9a73 --- /dev/null +++ b/Tools/ArdupilotMegaPlanner/Utilities/Constants/ParameterMetaDataConstants.cs @@ -0,0 +1,24 @@ +namespace ArdupilotMega.Utilities.Constants +{ + public sealed class ParameterMetaDataConstants + { + #region Markers + + public const string ParamDelimeter = "@"; + public const string PathDelimeter = ","; + public const string Param = "Param"; + public const string Lib = "Lib"; + 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 + } +} diff --git a/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataParser.cs b/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataParser.cs index a737da4f53..1d68825371 100644 --- a/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataParser.cs +++ b/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataParser.cs @@ -7,14 +7,15 @@ using System.Net; using System.Text.RegularExpressions; using System.Windows.Forms; using System.Xml; -using ArdupilotMega.Constants; +using ArdupilotMega.Utilities.Constants; 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); @@ -35,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); - var request = WebRequest.Create(parameterLocation); + // Read and parse the content. + string dataFromAddress = ReadDataFromAddress(parameterLocation); + ParseLibInformation(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(); } @@ -91,6 +57,67 @@ namespace ArdupilotMega.Utilities } } + /// + /// Parses the lib information. + /// + /// The file contents. + /// The obj XML text writer. + /// The parameter location. + private static void ParseLibInformation(string fileContents, XmlTextWriter objXmlTextWriter, string parameterLocation) + { + var parsedInformation = ParseKeyValuePairs(fileContents, ParameterMetaDataConstants.Lib); + 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. /// @@ -98,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) { @@ -114,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) { @@ -124,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; } /// @@ -189,5 +261,58 @@ namespace ArdupilotMega.Utilities } } } + + /// + /// Reads the data from address. + /// + /// The address. + /// + private static string ReadDataFromAddress(string address) + { + string data = string.Empty; + + log.Info(address); + + 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; + } } }