ardupilot/Tools/ArdupilotMegaPlanner/Utilities/ParameterMetaDataParser.cs
Michael Oborne 944488afaf APM Planner 1.1.99
Convert to IActivate, IDeactivate scheme, thanks andrew
add support for rfcomm* interfaces on linux
fix guage off screen draw mono issue.
remove use of BackStageViewContentPanel
andrews spacer changes - not using dues to screen space issue
change configpanel constructor to load xml directly
remove IMavlink Interface
fix hsi off screen draw issue on mono
modify hud to use sprite fonts, instead of drawing via GDI+
modify progress reporter to use a 10hz timer to update screen, using invoke/begininvoke fails on mono at 50hz (over 100ms per call).
fix targetalt and target airspeed jumping issue.
lots of cleanup on tab switching, ie stoping timers/other
3dr radio status led update
update ardurover car icon
speedup georef image screen. tested on over 1000 images.
2012-07-22 15:51:05 +08:00

350 lines
16 KiB
C#

using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
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}(?<MetaKey>[^:]+):(?<MetaValue>.+)", ParameterMetaDataConstants.ParamDelimeter));
private static readonly Regex _parentDirectoryRegex = new Regex("(?<ParentDirectory>[../]*)(?<Path>.+)");
private static readonly ILog log =
LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static void GetParameterInformation()
{
string parameterLocationsString = ConfigurationManager.AppSettings["ParameterLocations"];
if(!String.IsNullOrEmpty(parameterLocationsString))
{
var parameterLocations = parameterLocationsString.Split(';').ToList();
parameterLocations.RemoveAll(String.IsNullOrEmpty);
string sStartupPath = Application.StartupPath;
using (var objXmlTextWriter = new XmlTextWriter(String.Format("{0}{1}{2}", Application.StartupPath, Path.DirectorySeparatorChar, ConfigurationManager.AppSettings["ParameterMetaDataXMLFileName"]), null))
{
objXmlTextWriter.Formatting = Formatting.Indented;
objXmlTextWriter.WriteStartDocument();
objXmlTextWriter.WriteStartElement("Params");
foreach (string parameterLocation in parameterLocations)
{
string element = "none";
if (parameterLocation.ToLower().Contains("arducopter")) {
element = MainV2.Firmwares.ArduCopter2.ToString();
} else if (parameterLocation.ToLower().Contains("arduplane")) {
element = MainV2.Firmwares.ArduPlane.ToString();
} else if (parameterLocation.ToLower().Contains("rover")) {
element = MainV2.Firmwares.ArduRover.ToString();
}
// Write the start element for this parameter location
objXmlTextWriter.WriteStartElement(element);
// Read and parse the content.
string dataFromAddress = ReadDataFromAddress(parameterLocation);
ParseGroupInformation(dataFromAddress, objXmlTextWriter, parameterLocation);
ParseParameterInformation(dataFromAddress, objXmlTextWriter);
// Write the end element for this parameter location
objXmlTextWriter.WriteEndElement();
}
objXmlTextWriter.WriteEndElement();
// Clear the stream
objXmlTextWriter.WriteEndDocument();
objXmlTextWriter.Flush();
objXmlTextWriter.Close();
}
}
}
/// <summary>
/// Parses the group parameter information.
/// </summary>
/// <param name="fileContents">The file contents.</param>
/// <param name="objXmlTextWriter">The obj XML text writer.</param>
/// <param name="parameterLocation">The parameter location.</param>
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 =>
{
log.Info("Process "+ node.Key + " : " + 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);
}
}
}));
}
});
}
}
/// <summary>
/// Parses the parameter information.
/// </summary>
/// <param name="fileContents">The file contents.</param>
/// <param name="objXmlTextWriter">The obj XML text writer.</param>
private static void ParseParameterInformation(string fileContents, XmlTextWriter objXmlTextWriter)
{
ParseParameterInformation(fileContents, objXmlTextWriter, string.Empty);
}
/// <summary>
/// Parses the parameter information.
/// </summary>
/// <param name="fileContents">The file contents.</param>
/// <param name="objXmlTextWriter">The obj XML text writer.</param>
/// <param name="parameterPrefix">The parameter prefix.</param>
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();
});
}
}
/// <summary>
/// Parses the parameter information.
/// </summary>
/// <param name="fileContents">The file contents.</param>
/// <param name="nodeKey">The node key.</param>
/// <returns></returns>
private static Dictionary<string, Dictionary<string, string>> ParseKeyValuePairs(string fileContents, string nodeKey)
{
var returnDict = new Dictionary<string, Dictionary<string, string>>();
var indicies = new List<int>();
GetIndexOfMarkers(ref indicies, fileContents, ParameterMetaDataConstants.ParamDelimeter + nodeKey, 0);
if(indicies.Count > 0)
{
// Loop through the indicies of the parameter comments found
for(int i = 0; i < indicies.Count; i++)
{
// 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 stopIdx = (i == indicies.Count - 1) ? fileContents.Length : indicies[i + 1] + 1;
string subStringToSearch = fileContents.Substring(indicies[i], (stopIdx - indicies[i]));
if(!String.IsNullOrEmpty(subStringToSearch))
{
var metaIndicies = new List<int>();
GetIndexOfMarkers(ref metaIndicies, subStringToSearch, ParameterMetaDataConstants.ParamDelimeter, 0);
if(metaIndicies.Count > 0)
{
// This meta param key
var paramNameKey = subStringToSearch.Substring(metaIndicies[0], (metaIndicies[1] - metaIndicies[0]));
// Match based on the regex defined at the top of this class
Match paramNameKeyMatch = _paramMetaRegex.Match(paramNameKey);
if (paramNameKeyMatch.Success && paramNameKeyMatch.Groups["MetaKey"].Value == nodeKey)
{
string key = paramNameKeyMatch.Groups["MetaValue"].Value.Trim(new char[] {' '});
var metaDict = new Dictionary<string, string>();
if(!returnDict.ContainsKey(key))
{
// Loop through the indicies of the meta data found
for (int x = 1; x < metaIndicies.Count; x++)
{
// 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] + 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[] { ' ' }));
}
}
}
}
if (!returnDict.ContainsKey(key))
{
returnDict.Add(key, metaDict);
}
else
{
log.Error("Duplicate Key " + key);
}
}
}
}
}
}
return returnDict;
}
/// <summary>
/// Gets the index of param markers.
/// </summary>
/// <param name="indicies">The indicies.</param>
/// <param name="inspectThis">The string to be inspected for a parameter.</param>
/// <param name="delimeter">The delimeter.</param>
/// <param name="prevIdx">The prev idx.</param>
private static void GetIndexOfMarkers(ref List<int> indicies, string inspectThis, string delimeter, int prevIdx)
{
// Find the index of the start of a parameter comment
int idx = inspectThis.IndexOf(delimeter, prevIdx, StringComparison.InvariantCultureIgnoreCase);
// If we can't find one we stop here
if(idx != -1)
{
// Add the index we found
indicies.Add(idx);
// Move the index after the parameter delimeter
int newIdx = idx + delimeter.Length;
// If we have more string to inspect
if(newIdx < inspectThis.Length)
{
// Recursively search for the next index
GetIndexOfMarkers(ref indicies, inspectThis, delimeter, newIdx);
}
}
}
/// <summary>
/// Reads the data from address.
/// </summary>
/// <param name="address">The address.</param>
/// <returns></returns>
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;
}
}
}