/// <summary> /// Parses a saved configuration file and returns a UscSettings object. /// </summary> /// <param name="warnings">A list of warnings. Whenever something goes /// wrong with the file loading, a warning will be added to this list. /// The warnings are not fatal; if the function returns it will return /// a valid UscSettings object. /// </param> /// <param name="sr">The file to read from.</param> /// <remarks>This function is messy. Maybe I should have tried the XPath /// library.</remarks> public static UscSettings load(StreamReader sr, List<String> warnings) { XmlReader reader = XmlReader.Create(sr); UscSettings settings = new UscSettings(); string script = ""; // The x prefix means "came directly from XML" Dictionary<String, String> xParams = new Dictionary<string, string>(); // Only read the data inside the UscSettings element. reader.ReadToFollowing("UscSettings"); readAttributes(reader, xParams); reader = reader.ReadSubtree(); // Check the version number if (!xParams.ContainsKey("version")) { warnings.Add("This file has no version number, so it might have been read incorrectly."); } else if (xParams["version"] != "1") { warnings.Add("Unrecognized settings file version \"" + xParams["version"] + "\"."); } reader.Read(); // this is needed, otherwise the first tag inside uscSettings doesn't work work (not sure why) while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element && reader.Name == "Channels") { // We found the Channels tag. // Read the ServosAvailable and ServoPeriod attributes from it in to our collection. readAttributes(reader, xParams); // Make a reader that can only read the stuff inside the Channels tag. var channelsReader = reader.ReadSubtree(); // For each Channel tag... while(channelsReader.ReadToFollowing("Channel")) { // Read all the attributes. Dictionary<String, String> xChannel = new Dictionary<string, string>(); readAttributes(channelsReader, xChannel); // Transform the attributes in to a ChannelSetting object. ChannelSetting cs = new ChannelSetting(); if (assertKey("name", xChannel, warnings)) { cs.name = xChannel["name"]; } if (assertKey("mode", xChannel, warnings)) { switch (xChannel["mode"].ToLower()) { case "servomultiplied": cs.mode = ChannelMode.ServoMultiplied; break; case "servo": cs.mode = ChannelMode.Servo; break; case "input": cs.mode = ChannelMode.Input; break; case "output": cs.mode = ChannelMode.Output; break; default: warnings.Add("Invalid mode \"" + xChannel["mode"] + "\"."); break; } } if (assertKey("homemode", xChannel, warnings)) { switch (xChannel["homemode"].ToLower()) { case "goto": cs.homeMode = HomeMode.Goto; break; case "off": cs.homeMode = HomeMode.Off; break; case "ignore": cs.homeMode = HomeMode.Ignore; break; default: warnings.Add("Invalid homemode \"" + xChannel["homemode"] + "\"."); break; } } if (assertKey("min", xChannel, warnings)) { parseU16(xChannel["min"], ref cs.minimum, "min", warnings); } if (assertKey("max", xChannel, warnings)) { parseU16(xChannel["max"], ref cs.maximum, "max", warnings); } if (assertKey("home", xChannel, warnings)) { parseU16(xChannel["home"], ref cs.home, "home", warnings); } if (assertKey("speed", xChannel, warnings)) { parseU16(xChannel["speed"], ref cs.speed, "speed", warnings); } if (assertKey("acceleration", xChannel, warnings)) { parseU8(xChannel["acceleration"], ref cs.acceleration, "acceleration", warnings); } if (assertKey("neutral", xChannel, warnings)) { parseU16(xChannel["neutral"], ref cs.neutral, "neutral", warnings); } if (assertKey("range", xChannel, warnings)) { parseU16(xChannel["range"], ref cs.range, "range", warnings); } settings.channelSettings.Add(cs); } if (channelsReader.ReadToFollowing("Channel")) { warnings.Add("More than " + settings.servoCount + " channel elements were found. The extra elements have been discarded."); } } else if (reader.NodeType == XmlNodeType.Element && reader.Name == "Sequences") { // We found the Sequences tag. // For each Sequence tag in this sequence... var sequencesReader = reader.ReadSubtree(); while (sequencesReader.ReadToFollowing("Sequence")) { // Create a new sequence. Sequence sequence = new Sequence(); settings.sequences.Add(sequence); // Read the sequence tag attributes (should just be "name"). Dictionary<String, String> sequenceAttributes = new Dictionary<string, string>(); readAttributes(sequencesReader, sequenceAttributes); if (sequenceAttributes.ContainsKey("name")) { sequence.name = sequenceAttributes["name"]; } else { sequence.name = "Sequence " + settings.sequences.Count; warnings.Add("No name found for sequence " + sequence.name + "."); } // For each frame tag in this sequence... var framesReader = reader.ReadSubtree(); while (framesReader.ReadToFollowing("Frame")) { // Create a new frame. Frame frame = new Frame(); sequence.frames.Add(frame); // Read the frame attributes from XML (name, duration) Dictionary<String, String> frameAttributes = new Dictionary<string, string>(); readAttributes(framesReader, frameAttributes); if (frameAttributes.ContainsKey("name")) { frame.name = frameAttributes["name"]; } else { frame.name = "Frame " + sequence.frames.Count; warnings.Add("No name found for " + frame.name + " in sequence \"" + sequence.name + "\"."); } if (frameAttributes.ContainsKey("duration")) { parseU16(frameAttributes["duration"], ref frame.length_ms, "Duration for frame \"" + frame.name + "\" in sequence \"" + sequence.name + "\".", warnings); } else { frame.name = "Frame " + sequence.frames.Count; warnings.Add("No duration found for frame \"" + frame.name + "\" in sequence \"" + sequence.name + "\"."); } frame.setTargetsFromString(reader.ReadElementContentAsString(), settings.servoCount); } } } else if (reader.NodeType == XmlNodeType.Element && reader.Name == "Script") { // We found the <Script> tag. // Get the ScriptDone attribute in to our dictionary. readAttributes(reader, xParams); // Read the script. script = reader.ReadElementContentAsString(); } else if (reader.NodeType == XmlNodeType.Element) { // Read the miscellaneous parameters that come in element tags, like <NeverSuspend>false</NeverSuspend>. try { xParams[reader.Name] = reader.ReadElementContentAsString(); } catch (XmlException e) { warnings.Add("Unable to parse element \"" + reader.Name + "\": " + e.Message); } } } reader.Close(); //// Step 2: Put the data in to the settings object. try { settings.setAndCompileScript(script); } catch (Exception e) { warnings.Add("Error compiling script from XML file: " + e.Message); settings.scriptInconsistent = true; } if (assertKey("NeverSuspend", xParams, warnings)) { parseBool(xParams["NeverSuspend"], ref settings.neverSuspend, "NeverSuspend", warnings); } if (assertKey("SerialMode", xParams, warnings)) { switch (xParams["SerialMode"]) { default: settings.serialMode = uscSerialMode.SERIAL_MODE_UART_DETECT_BAUD_RATE; break; case "UART_FIXED_BAUD_RATE": settings.serialMode = uscSerialMode.SERIAL_MODE_UART_FIXED_BAUD_RATE; break; case "USB_DUAL_PORT": settings.serialMode = uscSerialMode.SERIAL_MODE_USB_DUAL_PORT; break; case "USB_CHAINED": settings.serialMode = uscSerialMode.SERIAL_MODE_USB_CHAINED; break; } } if (assertKey("FixedBaudRate", xParams, warnings)) { parseU32(xParams["FixedBaudRate"], ref settings.fixedBaudRate, "FixedBaudRate", warnings); } if (assertKey("SerialTimeout", xParams, warnings)) { parseU16(xParams["SerialTimeout"], ref settings.serialTimeout, "SerialTimeout", warnings); } if (assertKey("EnableCrc", xParams, warnings)) { parseBool(xParams["EnableCrc"], ref settings.enableCrc, "EnableCrc", warnings); } if (assertKey("SerialDeviceNumber", xParams, warnings)) { parseU8(xParams["SerialDeviceNumber"], ref settings.serialDeviceNumber, "SerialDeviceNumber", warnings); } if (assertKey("SerialMiniSscOffset", xParams, warnings)) { parseU8(xParams["SerialMiniSscOffset"], ref settings.miniSscOffset, "SerialMiniSscOffset", warnings); } if (assertKey("ScriptDone", xParams, warnings)) { parseBool(xParams["ScriptDone"], ref settings.scriptDone, "ScriptDone", warnings); } // These parameters are optional because they don't apply to all Maestros. if (xParams.ContainsKey("ServosAvailable")) { parseU8(xParams["ServosAvailable"], ref settings.servosAvailable, "ServosAvailable", warnings); } if (xParams.ContainsKey("ServoPeriod")) { parseU8(xParams["ServoPeriod"], ref settings.servoPeriod, "ServoPeriod", warnings); } if (xParams.ContainsKey("EnablePullups")) { parseBool(xParams["EnablePullups"], ref settings.enablePullups, "EnablePullups", warnings); } if (xParams.ContainsKey("MiniMaestroServoPeriod")) { parseU32(xParams["MiniMaestroServoPeriod"], ref settings.miniMaestroServoPeriod, "MiniMaestroServoPeriod", warnings); } if (xParams.ContainsKey("ServoMultiplier")) { parseU16(xParams["ServoMultiplier"], ref settings.servoMultiplier, "ServoMultiplier", warnings); } return settings; }
public static List<Frame> getFromClipboard() { Frame[] frameArray = Clipboard.GetData("Pololu.Usc.Sequencer.Frame[]") as Frame[]; if (frameArray != null) { return new List<Frame>(frameArray); } Frame frameDirect = Clipboard.GetData("Pololu.Usc.Sequencer.Frame") as Frame; if (frameDirect != null) { return new List<Frame> { frameDirect }; } if (Clipboard.ContainsText()) { // Tab-separated-values for interop with spreadsheet programs. List<Frame> frames = new List<Frame>(); String[] rows = Clipboard.GetText().Split('\n'); foreach (String row in rows) { String[] parts = row.Split('\t'); if (parts.Length < 3) { // There are not enough tab-separated parts available // for name, duration, and one target so this line has // no chance of being a frame. Go to the next line. continue; } Frame frame = new Frame(); frame.name = parts[0]; // Prevent importing ridiculously long names. if (frame.name.Length > 80) { frame.name = frame.name.Substring(0, 80); } try { frame.length_ms = ushort.Parse(parts[1]); } catch { frame.length_ms = 500; } List<ushort> targets = new List<ushort>(); for (int i = 2; i < parts.Length; i++) { try { targets.Add(ushort.Parse(parts[i])); } catch { targets.Add(0); } } frame.targets = targets.ToArray(); frames.Add(frame); } return frames; } return null; }