diff --git a/libEDSsharp/CanOpenEDS.cs b/libEDSsharp/CanOpenEDS.cs new file mode 100644 index 00000000..d4be60f6 --- /dev/null +++ b/libEDSsharp/CanOpenEDS.cs @@ -0,0 +1,1389 @@ +/* + This file is part of libEDSsharp. + + libEDSsharp is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + libEDSsharp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libEDSsharp. If not, see . + + Copyright(c) 2016 - 2019 Robin Cornelius +*/ + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Text.RegularExpressions; + +namespace libEDSsharp +{ + public partial class InfoSection + { + public virtual void Parse(Dictionary section, string sectionname) + { + this.section = section; + + FieldInfo[] fields = this.GetType().GetFields(); + + foreach (FieldInfo f in fields) + { + if (Attribute.IsDefined(f, typeof(EdsExport))) + GetField(f.Name, f.Name); + + if (Attribute.IsDefined(f, typeof(DcfExport))) + GetField(f.Name, f.Name); + } + } + + /// + /// Write object to stream + /// + /// stream to write the data to + /// file type + public void Write(StreamWriter writer, Filetype ft) + { + writer.WriteLine("[" + edssection + "]"); + Type tx = this.GetType(); + FieldInfo[] fields = this.GetType().GetFields(); + + foreach (FieldInfo f in fields) + { + if ((ft == Filetype.File_EDS) && (!Attribute.IsDefined(f, typeof(EdsExport)))) + continue; + + if ((ft == Filetype.File_DCF) && (!(Attribute.IsDefined(f, typeof(DcfExport)) || Attribute.IsDefined(f, typeof(EdsExport))))) + continue; + + if (f.GetValue(this) == null) + continue; + + EdsExport ex = (EdsExport)f.GetCustomAttribute(typeof(EdsExport)); + + bool comment = ex.IsReadOnly(); + + if (f.FieldType.Name == "Boolean") + { + writer.WriteLine(string.Format("{2}{0}={1}", f.Name, ((bool)f.GetValue(this)) == true ? 1 : 0, comment == true ? ";" : "")); + } + else + { + writer.WriteLine(string.Format("{2}{0}={1}", f.Name, f.GetValue(this).ToString(), comment == true ? ";" : "")); + } + } + + writer.WriteLine(""); + } + } + + public partial class MandatoryObjects : SupportedObjects + { + public MandatoryObjects(Dictionary section) + : this() + { + Parse(section); + } + } + + public partial class OptionalObjects : SupportedObjects + { + public OptionalObjects(Dictionary section) + : this() + { + Parse(section); + } + } + + public partial class ManufacturerObjects : SupportedObjects + { + public ManufacturerObjects(Dictionary section) + : this() + { + Parse(section); + } + } + + public partial class TypeDefinitions : SupportedObjects + { + public TypeDefinitions(Dictionary section) + { + Parse(section); + } + } + + public partial class SupportedObjects + { + public virtual void Parse(Dictionary section) + { + objectlist = new Dictionary(); + foreach (KeyValuePair kvp in section) + { + if (kvp.Key.ToLower() == "supportedobjects") + continue; + + if (kvp.Key.ToLower() == "nrofentries") + continue; + + int count = Convert.ToInt16(kvp.Key, EDSsharp.Getbase(kvp.Key)); + int target = Convert.ToInt16(kvp.Value, EDSsharp.Getbase(kvp.Value)); + objectlist.Add(count, target); + } + } + /// + /// Write object to stream + /// + /// stream to write the data to + public void Write(StreamWriter writer) + { + writer.WriteLine("[" + edssection + "]"); + writer.WriteLine(string.Format("{0}={1}", countmsg, objectlist.Count)); + foreach (KeyValuePair kvp in objectlist) + { + writer.WriteLine(string.Format("{0}=0x{1:X4}", kvp.Key, kvp.Value)); + } + writer.WriteLine(""); + } + } + + public partial class Comments + { + public Comments(Dictionary section) + { + Parse(section); + } + + public virtual void Parse(Dictionary section) + { + comments = new List(); + foreach (KeyValuePair kvp in section) + { + if (kvp.Key == "Lines") + continue; + + comments.Add(kvp.Value); + } + } + /// + /// Write object to stream + /// + /// stream to write the data to + public void Write(StreamWriter writer) + { + if (comments == null) + { + comments = new List(); + } + + writer.WriteLine("[" + edssection + "]"); + + writer.WriteLine(string.Format("Lines={0}", comments.Count)); + + int count = 1; + foreach (string s in comments) + { + writer.WriteLine(string.Format("Line{0}={1}", count, s)); + count++; + } + + writer.WriteLine(""); + } + } + public partial class Dummyusage : InfoSection + { + public Dummyusage(Dictionary section) : this() + { + Parse(section, edssection); + } + } + + /// + /// FileInfo section as described in CiA 306 + /// + public partial class FileInfo : InfoSection + { + public FileInfo(Dictionary section) : this() + { + Parse(section, edssection); + } + + override public void Parse(Dictionary section, string sectionname) + { + base.Parse(section, edssection); + + string dtcombined = ""; + try + { + if (section.ContainsKey("CreationTime") && section.ContainsKey("CreationDate")) + { + dtcombined = section["CreationTime"].Replace(" ", "") + " " + section["CreationDate"]; + CreationDateTime = DateTime.ParseExact(dtcombined, "h:mmtt MM-dd-yyyy", CultureInfo.InvariantCulture); + } + } + catch (Exception e) + { + if (e is System.FormatException) + { + Warnings.warning_list.Add(String.Format("EDS Error: Section [{1}] Unable to parse DateTime {0} for CreationTime, not in DS306 format", dtcombined, sectionname)); + } + } + + try + { + if (section.ContainsKey("ModificationTime") && section.ContainsKey("ModificationTime")) + { + dtcombined = section["ModificationTime"].Replace(" ", "") + " " + section["ModificationDate"]; + ModificationDateTime = DateTime.ParseExact(dtcombined, "h:mmtt MM-dd-yyyy", CultureInfo.InvariantCulture); + } + } + catch (Exception e) + { + if (e is System.FormatException) + { + Warnings.warning_list.Add(String.Format("EDS Error: Section [{1}] Unable to parse DateTime {0} for ModificationTime, not in DS306 format", dtcombined, sectionname)); + } + } + + + try + { + if (section.ContainsKey("EDSVersion")) + { + string[] bits = section["EDSVersion"].Split('.'); + if (bits.Length >= 1) + EDSVersionMajor = Convert.ToByte(bits[0]); + if (bits.Length >= 2) + EDSVersionMinor = Convert.ToByte(bits[1]); + //EDSVersion = String.Format("{0}.{1}", EDSVersionMajor, EDSVersionMinor); + } + } + catch + { + Warnings.warning_list.Add(String.Format("Unable to parse EDS version {0}", section["EDSVersion"])); + } + } + } + public partial class DeviceInfo : InfoSection + { + public DeviceInfo(Dictionary section) : this() + { + Parse(section, edssection); + } + } + + public partial class DeviceCommissioning : InfoSection + { + public DeviceCommissioning(Dictionary section) : this() + { + Parse(section, edssection); + } + + } + public partial class SupportedModules : InfoSection + { + public SupportedModules(Dictionary section) : this() + { + Parse(section, edssection); + } + } + + public partial class ConnectedModules : SupportedObjects + { + public ConnectedModules(Dictionary section) : this() + { + Parse(section); + + foreach (KeyValuePair kvp in this.objectlist) + { + UInt16 K = (UInt16)kvp.Value; + UInt16 V = (UInt16)kvp.Key; + + connectedmodulelist.Add(K, V); + } + } + } + public partial class MxFixedObjects : SupportedObjects + { + public MxFixedObjects(Dictionary section, UInt16 modindex) : this(modindex) + { + Parse(section); + + foreach (KeyValuePair kvp in this.objectlist) + { + connectedmodulelist.Add((UInt16)kvp.Value, (UInt16)kvp.Key); + } + } + } + + public partial class ModuleInfo : InfoSection + { + public ModuleInfo(Dictionary section, UInt16 moduleindex) : this(moduleindex) + { + Parse(section, edssection); + } + } + + public partial class ModuleComments : Comments + { + public ModuleComments(Dictionary section, UInt16 moduleindex) : this(moduleindex) + { + Parse(section); + } + } + + public partial class ModuleSubExtends : SupportedObjects + { + public ModuleSubExtends(Dictionary section, UInt16 moduleindex) + : this(moduleindex) + { + Parse(section); + } + } + + public partial class ODentry + { + /// + /// Write out this Object dictionary entry to an EDS/DCF file using correct formatting + /// + /// Handle to the stream writer to write to + /// File type being written + /// OD type to write + /// module + public void Write(StreamWriter writer, InfoSection.Filetype ft, Odtype odt = Odtype.NORMAL, int module = 0) + { + string fixedmodheader = ""; + + if (odt == Odtype.FIXED) + { + fixedmodheader = string.Format("M{0}Fixed", module); + } + + if (odt == Odtype.SUBEXT) + { + fixedmodheader = string.Format("M{0}SubExt", module); + } + + if (parent != null) + { + writer.WriteLine(string.Format("[{0}{1:X}sub{2:X}]", fixedmodheader, Index, Subindex)); + } + else + { + writer.WriteLine(string.Format("[{0}{1:X}]", fixedmodheader, Index)); + } + + writer.WriteLine(string.Format("ParameterName={0}", parameter_name)); + + if (ft == InfoSection.Filetype.File_DCF) + { + writer.WriteLine(string.Format("Denotation={0}", denotation)); + } + + writer.WriteLine(string.Format("ObjectType=0x{0:X}", (int)objecttype)); + writer.WriteLine(string.Format(";StorageLocation={0}", prop.CO_storageGroup)); + + if (objecttype == ObjectType.ARRAY) + { + writer.WriteLine(string.Format("SubNumber=0x{0:X}", Nosubindexes)); + } + + if (objecttype == ObjectType.RECORD) + { + writer.WriteLine(string.Format("SubNumber=0x{0:X}", Nosubindexes)); + } + + if (objecttype == ObjectType.VAR) + { + DataType dt = datatype; + if (dt == DataType.UNKNOWN && this.parent != null) + dt = parent.datatype; + writer.WriteLine(string.Format("DataType=0x{0:X4}", (int)dt)); + writer.WriteLine(string.Format("AccessType={0}", accesstype.ToString())); + + if (HighLimit != null && HighLimit != "") + { + writer.WriteLine(string.Format("HighLimit={0}", Formatoctetstring(HighLimit))); + } + + if (LowLimit != null && LowLimit != "") + { + writer.WriteLine(string.Format("LowLimit={0}", Formatoctetstring(LowLimit))); + } + + writer.WriteLine(string.Format("DefaultValue={0}", Formatoctetstring(defaultvalue))); + + //TODO If the ObjectType is domain (0x2) the value of the object may be stored in a file,UploadFile and DownloadFile + if (ft == InfoSection.Filetype.File_DCF) + { + writer.WriteLine(string.Format("ParameterValue={0}", Formatoctetstring(actualvalue))); + } + + writer.WriteLine(string.Format("PDOMapping={0}", PDOMapping == true ? 1 : 0)); + + if (prop.CO_flagsPDO == true) + { + writer.WriteLine(";TPDODetectCos=1"); + } + } + + //Count is for modules in the [MxSubExtxxxx] + //Should we export this on EDS only, or DCF or both? + if (odt == Odtype.SUBEXT) + { + writer.WriteLine(string.Format("Count={0}", count)); + writer.WriteLine(string.Format("ObjExtend={0}", ObjExtend)); + } + + //ObjectFlags is always optional (Page 15, DSP306) and used for DCF writing to nodes + //also recommended not to write if it is already 0 + if (ObjFlags != 0) + { + writer.WriteLine(string.Format("ObjFlags={0}", ObjFlags)); + } + + writer.WriteLine(""); + } + } + public partial class EDSsharp + { + public void Parseline(string linex, int no) + { + string key = ""; + string value = ""; + + string line = linex.TrimStart(';'); + bool custom_extension = false; + + if (linex == null || linex == "") + return; + + if (linex[0] == ';') + custom_extension = true; + + //extract sections + { + string pat = @"^\[([a-z0-9]+)\]"; + + Regex r = new Regex(pat, RegexOptions.IgnoreCase); + Match m = r.Match(line); + if (m.Success) + { + Group g = m.Groups[1]; + sectionname = g.ToString(); + + if (!eds.ContainsKey(sectionname)) + { + eds.Add(sectionname, new Dictionary()); + } + else + { + Warnings.warning_list.Add(string.Format("EDS Error on Line {0} : Duplicate section [{1}] ", no, sectionname)); + } + } + } + + //extract keyvalues + { + //Bug #70 Eat whitespace! + string pat = @"^([a-z0-9_]+)[ ]*=[ ]*(.*)"; + + Regex r = new Regex(pat, RegexOptions.IgnoreCase); + Match m = r.Match(line); + if (m.Success) + { + key = m.Groups[1].ToString(); + value = m.Groups[2].ToString(); + value = value.TrimEnd(' ', '\t', '\n', '\r'); + + //not sure how we actually get here with out a section being in the dictionary already.. + //suspect this is dead code. + if (!eds.ContainsKey(sectionname)) + { + eds.Add(sectionname, new Dictionary()); + } + + if (custom_extension == false) + { + try + { + eds[sectionname].Add(key, value); + } + catch (Exception) + { + Warnings.warning_list.Add(string.Format("EDS Error on Line {3} : Duplicate key \"{0}\" value \"{1}\" in section [{2}]", key, value, sectionname, no)); + } + } + else + //Only allow our own extensions to populate the key/value pair + { + if (key == "StorageLocation" || key == "TPDODetectCos") + { + try + { + eds[sectionname].Add(key, value); + } + catch (Exception) + { + Warnings.warning_list.Add(string.Format("EDS Error on Line {3} : Duplicate custom key \"{0}\" value \"{1}\" in section [{2}]", key, value, sectionname, no)); + } + } + } + } + } + } + + public void ParseEDSentry(KeyValuePair> kvp) + { + string section = kvp.Key; + + string pat = @"^(M[0-9a-fA-F]+(Fixed|SubExt))?([a-fA-F0-9]+)(sub)?([0-9a-fA-F]*)$"; + + Regex r = new Regex(pat); + Match m = r.Match(section); + if (m.Success) + { + SortedDictionary target = this.ods; + + //** MODULE DCF SUPPORT + + string pat2 = @"^M([0-9a-fA-F]+)(Fixed|SubExt)([0-9a-fA-F]+)"; + Regex r2 = new Regex(pat2, RegexOptions.IgnoreCase); + Match m2 = r2.Match(m.Groups[0].ToString()); + + if (m2.Success) + { + UInt16 modindex = 0, odindex = 0; + + try { modindex = Convert.ToUInt16(m2.Groups[1].Value); } + catch (Exception) { Console.WriteLine("** ALL GONE WRONG **" + m2.Groups[1].Value); } + //Indexes in the EDS are always in hex format without the pre 0x + try { odindex = Convert.ToUInt16(m2.Groups[3].Value, 16); } + catch (Exception) { Console.WriteLine("** ALL GONE WRONG **" + m2.Groups[3].Value); } + + + if (!modules.ContainsKey(modindex)) + modules.Add(modindex, new Module(modindex)); + + if (m2.Groups[2].ToString() == "SubExt") + { + target = modules[modindex].modulesubext; + } + else + { + target = modules[modindex].modulefixedobjects; + } + } + + ODentry od = new ODentry + { + //Indexes in the EDS are always in hex format without the pre 0x + Index = Convert.ToUInt16(m.Groups[3].ToString(), 16) + }; + + //Parameter name, mandatory always + if (!kvp.Value.ContainsKey("ParameterName")) + throw new ParameterException("Missing required field ParameterName on" + section); + od.parameter_name = kvp.Value["ParameterName"]; + + //Object type, assumed to be VAR unless specified + if (kvp.Value.ContainsKey("ObjectType")) + { + int type = Convert.ToInt16(kvp.Value["ObjectType"], Getbase(kvp.Value["ObjectType"])); + od.objecttype = (ObjectType)type; + } + else + { + od.objecttype = ObjectType.VAR; + } + + if (kvp.Value.ContainsKey("CompactSubObj")) + { + od.CompactSubObj = Convert.ToByte(kvp.Value["CompactSubObj"], Getbase(kvp.Value["CompactSubObj"])); + } + + if (kvp.Value.ContainsKey("ObjFlags")) + { + od.ObjFlags = Convert.ToUInt32(kvp.Value["ObjFlags"], Getbase(kvp.Value["ObjFlags"])); + } + else + { + od.ObjFlags = 0; + } + + //Access Type + if (kvp.Value.ContainsKey("StorageLocation")) + { + od.prop.CO_storageGroup = kvp.Value["StorageLocation"]; + } + + if (kvp.Value.ContainsKey("TPDODetectCos")) + { + string test = kvp.Value["TPDODetectCos"].ToLower(); + if (test == "1" || test == "true") + { + od.prop.CO_flagsPDO = true; + } + else + od.prop.CO_flagsPDO = false; + } + + if (kvp.Value.ContainsKey("Count")) + { + /* FIXME: The format of "Count" is Unsigned8[; Unsigned8] according DS306 + * Count: + Number of extended Sub-Indexes with this description that are created per module. The format is Unsigned8 [; Unsigned8]. + If one or more Sub - Indexes are created per attached module to build a new sub- index, then Count is that + Number. In example 32 bit module creates 4 Sub - Indexes each having 8 Bit: Count = 4 + If several modules are gathered to form a new Sub- Index, then the number is 0, followed by semicolon and the + number of bits that are created per module to build a new Sub-Index.In example 2 bit modules with 8 bit objects: The + first Sub - Index is built upon modules 1 - 4, the next upon modules 5 - 8 etc.: Count = 0; 2.The objects are created, + when a new byte begins: Module 1 creates the Sub - Index 1; modules 2 - 4 fill it up; module 5 creates Sub-Index 2 and + so forth. + */ + pat2 = @"\s*([0-9a-fA-F]+)\s*;\s*([0-9a-fA-F]+)"; + r2 = new Regex(pat2, RegexOptions.IgnoreCase); + m2 = r2.Match(kvp.Value["Count"]); + + if (m2.Success) + { + Console.WriteLine("** FIXME Count format not supported ** Count: " + kvp.Value["Count"]); + int found = kvp.Value["Count"].IndexOf(";"); + string s = kvp.Value["Count"].Substring(found + 1); + try { od.count = Convert.ToByte(s, Getbase(s)); } + catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** Count" + kvp.Value["Count"]); } + } + else + { + try { od.count = Convert.ToByte(kvp.Value["Count"], Getbase(kvp.Value["Count"])); } + catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** Count" + kvp.Value["Count"]); } + } + } + + if (kvp.Value.ContainsKey("ObjExtend")) + { + try { od.ObjExtend = Convert.ToByte(kvp.Value["ObjExtend"]); } + catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** ObjExtend:" + kvp.Value["ObjExtend"]); } + } + + + if (od.objecttype == ObjectType.VAR) + { + if (kvp.Value.ContainsKey("CompactSubObj")) + throw new ParameterException("CompactSubObj not valid for a VAR Object, section: " + section); + + if (kvp.Value.ContainsKey("ParameterValue")) + { + try { od.actualvalue = kvp.Value["ParameterValue"]; } + catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** ParameterValue:" + kvp.Value["ParameterValue"]); } + } + + if (kvp.Value.ContainsKey("HighLimit")) + { + try { od.HighLimit = kvp.Value["HighLimit"]; } + catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** HighLimit:" + kvp.Value["HighLimit"]); } + } + + if (kvp.Value.ContainsKey("LowLimit")) + { + try { od.LowLimit = kvp.Value["LowLimit"]; } + catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** LowLimit:" + kvp.Value["LowLimit"]); } + } + + if (kvp.Value.ContainsKey("Denotation")) + { + try { od.denotation = kvp.Value["Denotation"]; } + catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** Denotation:" + kvp.Value["Denotation"]); } + } + + if (m.Groups[5].Length != 0) + { + //FIXME are subindexes in hex always? + UInt16 subindex = Convert.ToUInt16(m.Groups[5].ToString(), 16); + od.parent = target[od.Index]; + target[od.Index].subobjects.Add(subindex, od); + } + + if (!kvp.Value.ContainsKey("DataType")) + throw new ParameterException("Missing required field DataType on" + section); + od.datatype = (DataType)Convert.ToInt16(kvp.Value["DataType"], Getbase(kvp.Value["DataType"])); + + if (!kvp.Value.ContainsKey("AccessType")) + throw new ParameterException("Missing required AccessType on" + section); + + string accesstype = kvp.Value["AccessType"].ToLower(); + + if (Enum.IsDefined(typeof(AccessType), accesstype)) + { + od.accesstype = (AccessType)Enum.Parse(typeof(AccessType), accesstype); + } + else + { + throw new ParameterException("Unknown AccessType on" + section); + } + + if (kvp.Value.ContainsKey("DefaultValue")) + od.defaultvalue = kvp.Value["DefaultValue"]; + + od.PDOtype = PDOMappingType.no; + if (kvp.Value.ContainsKey("PDOMapping")) + { + bool pdo = Convert.ToInt16(kvp.Value["PDOMapping"], Getbase(kvp.Value["PDOMapping"])) == 1; + if (pdo == true) + od.PDOtype = PDOMappingType.optional; + } + } + + if (od.objecttype == ObjectType.RECORD || od.objecttype == ObjectType.ARRAY || od.objecttype == ObjectType.DEFSTRUCT) + { + if (od.CompactSubObj != 0) + { + if (!kvp.Value.ContainsKey("DataType")) + throw new ParameterException("Missing required field DataType on" + section); + od.datatype = (DataType)Convert.ToInt16(kvp.Value["DataType"], Getbase(kvp.Value["DataType"])); + + if (!kvp.Value.ContainsKey("AccessType")) + throw new ParameterException("Missing required AccessType on" + section); + string accesstype = kvp.Value["AccessType"]; + if (Enum.IsDefined(typeof(AccessType), accesstype)) + { + od.accesstype = (AccessType)Enum.Parse(typeof(AccessType), accesstype); + } + else + { + throw new ParameterException("Unknown AccessType on" + section); + } + + //now we generate CompactSubObj number of var objects below this parent + + if (od.CompactSubObj >= 0xfe) + { + od.CompactSubObj = 0xfe; + } + + ODentry subi = new ODentry("NrOfObjects", od.Index, DataType.UNSIGNED8, String.Format("0x{0:x2}", od.CompactSubObj), AccessType.ro, PDOMappingType.no, od); + od.subobjects.Add(0x00, subi); + + for (int x = 1; x <= od.CompactSubObj; x++) + { + string parameter_name = string.Format("{0}{1:x2}", od.parameter_name, x); + ODentry sub = new ODentry(parameter_name, od.Index, od.datatype, od.defaultvalue, od.accesstype, od.PDOtype, od); + + if (kvp.Value.ContainsKey("HighLimit")) + sub.HighLimit = kvp.Value["HighLimit"]; + + if (kvp.Value.ContainsKey("LowLimit")) + sub.HighLimit = kvp.Value["LowLimit"]; + + od.subobjects.Add((ushort)(x), sub); + } + } + else + { + if (!kvp.Value.ContainsKey("SubNumber")) + throw new ParameterException("Missing SubNumber on Array for" + section); + } + } + + if (od.objecttype == ObjectType.DOMAIN) + { + od.datatype = DataType.DOMAIN; + od.accesstype = AccessType.rw; + + if (kvp.Value.ContainsKey("DefaultValue")) + od.defaultvalue = kvp.Value["DefaultValue"]; + } + + //Only add top level to this list + if (m.Groups[5].Length == 0) + { + target.Add(od.Index, od); + } + } + } + + public void Loadfile(string filename) + { + projectFilename = filename; + + if (Path.GetExtension(filename).ToLower() == ".eds") + { + edsfilename = filename; + } + + if (Path.GetExtension(filename).ToLower() == ".dcf") + { + dcffilename = filename; + } + + int lineno = 1; + foreach (string linex in System.IO.File.ReadLines(filename)) + { + Parseline(linex, lineno); + lineno++; + } + + di = new DeviceInfo(eds["DeviceInfo"]); + + foreach (KeyValuePair> kvp in eds) + { + try { ParseEDSentry(kvp); } + catch (Exception) { Console.WriteLine("** ALL GONE WRONG **" + kvp); } + } + + fi = new FileInfo(eds["FileInfo"]); + if (eds.ContainsKey("DummyUsage")) + du = new Dummyusage(eds["DummyUsage"]); + + md = new MandatoryObjects(eds["MandatoryObjects"]); + + if (eds.ContainsKey("OptionalObjects")) + oo = new OptionalObjects(eds["OptionalObjects"]); + + if (eds.ContainsKey("ManufacturerObjects")) + mo = new ManufacturerObjects(eds["ManufacturerObjects"]); + + if (eds.ContainsKey("TypeDefinitions")) + td = new TypeDefinitions(eds["TypeDefinitions"]); + + //Only DCF not EDS files + dc = new DeviceCommissioning(); + string strSection = ""; + if (eds.ContainsKey("DeviceCommissioning")) // wrong section name as defined in the DSP302, but right spelling (for compabiltiy to some tools) + strSection = "DeviceCommissioning"; + else if (eds.ContainsKey("DeviceComissioning")) // right section name as defined in the DSP302, (wrong spelling) + strSection = "DeviceComissioning"; + + if (strSection != "") + { + dc.Parse(eds[strSection], "DeviceCommissioning"); + edsfilename = fi.LastEDS; + } + + c = new Comments(); + + if (eds.ContainsKey("Comments")) + c.Parse(eds["Comments"]); + + //Modules + + //FIXME + //we don't parse or support [MxFixedObjects] with MxFixedxxxx and MxFixedxxxxsubx + + if (eds.ContainsKey("SupportedModules")) + { + sm = new SupportedModules(eds["SupportedModules"]); + + //find MxModuleInfo + + foreach (string s in eds.Keys) + { + String pat = @"M([0-9]+)ModuleInfo"; + Regex r = new Regex(pat, RegexOptions.IgnoreCase); + Match m = r.Match(s); + + if (m.Success) + { + UInt16 modindex = Convert.ToUInt16(m.Groups[1].Value); + ModuleInfo mi = new ModuleInfo(eds[s], modindex); + + if (!modules.ContainsKey(modindex)) + modules.Add(modindex, new Module(modindex)); + + modules[modindex].mi = mi; + } + + pat = @"M([0-9]+)Comments"; + r = new Regex(pat, RegexOptions.IgnoreCase); + m = r.Match(s); + + if (m.Success) + { + UInt16 modindex = Convert.ToUInt16(m.Groups[1].Value); + ModuleComments mc = new ModuleComments(eds[s], modindex); + + if (!modules.ContainsKey(modindex)) + modules.Add(modindex, new Module(modindex)); + + modules[modindex].mc = mc; + } + pat = @"M([0-9]+)SubExtends"; + r = new Regex(pat, RegexOptions.IgnoreCase); + m = r.Match(s); + + if (m.Success) + { + UInt16 modindex = Convert.ToUInt16(m.Groups[1].Value); + ModuleSubExtends mse = new ModuleSubExtends(eds[s], modindex); + + if (!modules.ContainsKey(modindex)) + modules.Add(modindex, new Module(modindex)); + + modules[modindex].mse = mse; + } + + //DCF only + + pat = @"M([0-9]+)FixedObjects"; + r = new Regex(pat, RegexOptions.IgnoreCase); + m = r.Match(s); + + if (m.Success) + { + UInt16 modindex = Convert.ToUInt16(m.Groups[1].Value); + MxFixedObjects mxf = new MxFixedObjects(eds[s], modindex); + + if (!modules.ContainsKey(modindex)) + modules.Add(modindex, new Module(modindex)); + + modules[modindex].mxfo = mxf; + } + } + + if (eds.ContainsKey("ConnectedModules")) + { + cm = new ConnectedModules(eds["ConnectedModules"]); + } + + //COMPACT PDO + + if (di.CompactPDO != 0) + { + for (UInt16 index = 0x1400; index < 0x1600; index++) + { + ApplycompactPDO(index); + } + + for (UInt16 index = 0x1800; index < 0x1A00; index++) + { + ApplycompactPDO(index); + } + } + + ApplyimplicitPDO(); + } + // catch(Exception e) + //{ + // Console.WriteLine("** ALL GONE WRONG **" + e.ToString()); + // } + } + + void ApplycompactPDO(UInt16 index) + { + if (ods.ContainsKey(index)) + { + if ((!ods[index].Containssubindex(1)) && ((this.di.CompactPDO & 0x01) == 0)) + { + //Fill in cob ID + //FIX ME i'm really sure this is not correct, what default values should be used??? + string cob = string.Format("$NODEID + 0x180"); + ODentry subod = new ODentry("COB-ID", index, DataType.UNSIGNED32, cob, AccessType.rw, PDOMappingType.no, ods[index]); + ods[index].subobjects.Add(0x05, subod); + } + + if ((!ods[index].Containssubindex(2)) && ((this.di.CompactPDO & 0x02) == 0)) + { + //Fill in type + ODentry subod = new ODentry("Type", index, DataType.UNSIGNED8, "0xff", AccessType.rw, PDOMappingType.no, ods[index]); + ods[index].subobjects.Add(0x02, subod); + } + + if ((!ods[index].Containssubindex(3)) && ((this.di.CompactPDO & 0x04) == 0)) + { + //Fill in inhibit + ODentry subod = new ODentry("Inhibit time", index, DataType.UNSIGNED16, "0", AccessType.rw, PDOMappingType.no, ods[index]); + ods[index].subobjects.Add(0x03, subod); + } + + //NOT FOR RX PDO + if (index < 0x1800) + return; + + if ((!ods[index].Containssubindex(4)) && ((this.di.CompactPDO & 0x08) == 0)) + { + //Fill in compatibility entry + ODentry subod = new ODentry("Compatibility entry", index, DataType.UNSIGNED8, "0", AccessType.ro, PDOMappingType.no, ods[index]); + ods[index].subobjects.Add(0x04, subod); + } + + if ((!ods[index].Containssubindex(5)) && ((this.di.CompactPDO & 0x10) == 0)) + { + //Fill in event timer + ODentry subod = new ODentry("Event Timer", index, DataType.UNSIGNED16, "0", AccessType.rw, PDOMappingType.no, ods[index]); + ods[index].subobjects.Add(0x05, subod); + } + } + } + + /// + /// This function scans the PDO list and compares it to NrOfRXPDO and NrOfTXPDO + /// if these do not match in count then implicit PDOs are present and they are + /// filled in with default values from the lowest possible index + /// + protected void ApplyimplicitPDO() + { + UInt16 totalnorxpdos = di.NrOfRXPDO; + UInt16 totalnotxpdos = di.NrOfTXPDO; + + UpdatePDOcount(); + + UInt16 noexplicitrxpdos = di.NrOfRXPDO; + UInt16 noexplicittxpdos = di.NrOfTXPDO; + + //this is how many PDOS need generating on the fly + UInt16 noimplictrxpdos = (UInt16)(totalnorxpdos - noexplicitrxpdos); + UInt16 noimplicttxpdos = (UInt16)(totalnotxpdos - noexplicittxpdos); + + for (UInt16 index = 0x1400; (index < 0x1600) && (noimplictrxpdos > 0); index++) + { + if (!ods.ContainsKey(index)) + { + CreateRXPDO(index); + noimplictrxpdos--; + } + } + + for (UInt16 index = 0x1800; (index < 0x1A00) && (noimplicttxpdos > 0); index++) + { + if (!ods.ContainsKey(index)) + { + CreateTXPDO(index); + noimplicttxpdos--; + } + } + UpdatePDOcount(); + } + + public void Savefile(string filename, InfoSection.Filetype ft) + { + if (ft == InfoSection.Filetype.File_EDS) + this.edsfilename = filename; + + if (ft == InfoSection.Filetype.File_DCF) + { + this.dcffilename = filename; + fi.LastEDS = edsfilename; + } + + UpdatePDOcount(); + + //generate date times in DS306 format; h:mmtt MM-dd-yyyy + + fi.CreationDate = fi.CreationDateTime.ToString("MM-dd-yyyy", CultureInfo.InvariantCulture); + fi.CreationTime = fi.CreationDateTime.ToString("h:mmtt", CultureInfo.InvariantCulture); + + fi.ModificationDate = fi.ModificationDateTime.ToString("MM-dd-yyyy", CultureInfo.InvariantCulture); + fi.ModificationTime = fi.ModificationDateTime.ToString("h:mmtt", CultureInfo.InvariantCulture); + + fi.FileName = Path.GetFileName(filename); + + fi.EDSVersion = "4.0"; + fi.EDSVersionMajor = 4; + fi.EDSVersionMinor = 0; + + StreamWriter writer = System.IO.File.CreateText(filename); + writer.NewLine = "\n"; + fi.Write(writer, ft); + di.Write(writer, ft); + du.Write(writer, ft); + c.Write(writer); + + if (ft == InfoSection.Filetype.File_DCF) + { + dc.Write(writer, ft); + } + + //regenerate the object lists + md.objectlist.Clear(); + mo.objectlist.Clear(); + oo.objectlist.Clear(); + + foreach (KeyValuePair kvp in ods) + { + ODentry entry = kvp.Value; + + if (entry.prop.CO_disabled == true) + continue; + + if (entry.Index == 0x1000 || entry.Index == 0x1001 || entry.Index == 0x1018) + { + md.objectlist.Add(md.objectlist.Count + 1, entry.Index); + } + else + if (entry.Index >= 0x2000 && entry.Index < 0x6000) + { + mo.objectlist.Add(mo.objectlist.Count + 1, entry.Index); + } + else + { + oo.objectlist.Add(oo.objectlist.Count + 1, entry.Index); + } + } + + md.Write(writer); + + foreach (KeyValuePair kvp in ods) + { + ODentry od = kvp.Value; + if (md.objectlist.ContainsValue(od.Index)) + { + od.Write(writer, ft); + foreach (KeyValuePair kvp2 in od.subobjects) + { + ODentry od2 = kvp2.Value; + od2.Write(writer, ft); + } + } + } + + oo.Write(writer); + + foreach (KeyValuePair kvp in ods) + { + ODentry od = kvp.Value; + if (oo.objectlist.ContainsValue(od.Index)) + { + od.Write(writer, ft); + foreach (KeyValuePair kvp2 in od.subobjects) + { + ODentry od2 = kvp2.Value; + od2.Write(writer, ft); + } + } + } + + mo.Write(writer); + + foreach (KeyValuePair kvp in ods) + { + ODentry od = kvp.Value; + if (mo.objectlist.ContainsValue(od.Index)) + { + od.Write(writer, ft); + foreach (KeyValuePair kvp2 in od.subobjects) + { + ODentry od2 = kvp2.Value; + od2.Write(writer, ft); + } + } + } + + //modules + + if (sm.NrOfEntries > 0) + { + sm.Write(writer, ft); + + for (UInt16 moduleid = 1; moduleid <= sm.NrOfEntries; moduleid++) + { + modules[moduleid].mi.Write(writer, ft); + + modules[moduleid].mc.Write(writer); + + modules[moduleid].mse.Write(writer); + + foreach (KeyValuePair kvp2 in modules[moduleid].modulesubext) + { + ODentry od = kvp2.Value; + od.Write(writer, ft, ODentry.Odtype.SUBEXT, moduleid); + } + + modules[moduleid].mxfo.Write(writer); + + foreach (KeyValuePair kvp3 in modules[moduleid].modulefixedobjects) + { + ODentry od = kvp3.Value; + od.Write(writer, ft, ODentry.Odtype.SUBEXT, moduleid); + + foreach (KeyValuePair kvp4 in od.subobjects) + { + ODentry subod = kvp4.Value; + subod.Write(writer, ft, ODentry.Odtype.FIXED, moduleid); + } + } + } + } + + if (ft == InfoSection.Filetype.File_DCF) + { + if (cm.NrOfEntries > 0) + { + cm.Write(writer); + } + } + writer.Close(); + } + + //RX COM 0x1400 + //RX Map 0x1600 + //TX COM 0x1800 + //TX MAP 0x1a00 + + //call this with the comm param index not the mapping + bool CreatePDO(bool rx, UInt16 index) + { + //check if we are creating an RX PDO it is a valid index + if (rx && (index < 0x1400 || index >= 0x1600)) + return false; + + //check if we are creating an PDO TX it is a valid index + if (!rx & (index < 0x1800 || index >= 0x1A00)) + return false; + + //Check it does not already exist + if (ods.ContainsKey(index)) + return false; + + //check the associated mapping index does not exist + if (ods.ContainsKey((UInt16)(index + 0x200))) + return false; + + ODentry od_comparam; + ODentry od_mapping; + + if (rx) + { + od_comparam = new ODentry("RPDO communication parameter", index, 0) + { + Description = @"0x1400 - 0x15FF RPDO communication parameter +max sub-index + +COB - ID + bit 0 - 10: COB - ID for PDO, to change it bit 31 must be set + bit 11 - 29: set to 0 for 11 bit COB - ID + bit 30: 0(1) - rtr are allowed(are NOT allowed) for PDO + bit 31: 0(1) - node uses(does NOT use) PDO + +Transmission type + value = 0 - 240: receiving is synchronous, process after next reception of SYNC object + value = 241 - 253: not used + value = 254: manufacturer specific + value = 255: asynchronous" + }; + + od_mapping = new ODentry("RPDO mapping parameter", (UInt16)(index + 0x200), 0) + { + Description = @"0x1600 - 0x17FF RPDO mapping parameter (To change mapping, 'Number of mapped objects' must be set to 0) +Number of mapped objects + +mapped object (subindex 1...8) + bit 0 - 7: data length in bits + bit 8 - 15: subindex from OD + bit 16 - 31: index from OD" + }; + } + else + { + od_comparam = new ODentry("TPDO communication parameter", index, 0) + { + Description = @"0x1800 - 0x19FF TPDO communication parameter +max sub-index + +COB - ID + bit 0 - 10: COB - ID for PDO, to change it bit 31 must be set + bit 11 - 29: set to 0 for 11 bit COB - ID + bit 30: 0(1) - rtr are allowed(are NOT allowed) for PDO + bit 31: 0(1) - node uses(does NOT use) PDO + +Transmission type + value = 0: transmitting is synchronous, specification in device profile + value = 1 - 240: transmitting is synchronous after every N - th SYNC object + value = 241 - 251: not used + value = 252 - 253: Transmitted only on reception of Remote Transmission Request + value = 254: manufacturer specific + value = 255: asynchronous, specification in device profile + +inhibit time + bit 0 - 15: Minimum time between transmissions of the PDO in 100µs.Zero disables functionality. + +event timer + bit 0-15: Time between periodic transmissions of the PDO in ms.Zero disables functionality. + +SYNC start value + value = 0: Counter of the SYNC message shall not be processed. + value = 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message." + }; + + od_mapping = new ODentry("TPDO mapping parameter", (UInt16)(index + 0x200), 0) + { + Description = @"0x1A00 - 0x1BFF TPDO mapping parameter. (To change mapping, 'Number of mapped objects' must be set to 0). +Number of mapped objects + +mapped object (subindex 1...8) + bit 0 - 7: data length in bits + bit 8 - 15: subindex from OD + bit 16 - 31: index from OD" + }; + } + + od_comparam.objecttype = ObjectType.RECORD; + od_comparam.prop.CO_storageGroup = "ROM"; + od_comparam.accesstype = AccessType.ro; + od_comparam.PDOtype = PDOMappingType.no; + + ODentry sub; + + if (rx) + { + sub = new ODentry("max sub-index", index, DataType.UNSIGNED8, "2", AccessType.ro, PDOMappingType.no, od_comparam); + od_comparam.subobjects.Add(0, sub); + sub = new ODentry("COB-ID used by RPDO", index, DataType.UNSIGNED32, "$NODEID+0x200", AccessType.rw, PDOMappingType.no, od_comparam); + od_comparam.subobjects.Add(1, sub); + sub = new ODentry("transmission type", index, DataType.UNSIGNED8, "254", AccessType.rw, PDOMappingType.no, od_comparam); + od_comparam.subobjects.Add(2, sub); + } + else + { + sub = new ODentry("max sub-index", index, DataType.UNSIGNED8, "6", AccessType.ro, PDOMappingType.no, od_comparam); + od_comparam.subobjects.Add(0, sub); + sub = new ODentry("COB-ID used by TPDO", index, DataType.UNSIGNED32, "$NODEID+0x180", AccessType.rw, PDOMappingType.no, od_comparam); + od_comparam.subobjects.Add(1, sub); + sub = new ODentry("transmission type", index, DataType.UNSIGNED8, "254", AccessType.rw, PDOMappingType.no, od_comparam); + od_comparam.subobjects.Add(2, sub); + sub = new ODentry("inhibit time", index, DataType.UNSIGNED16, "0", AccessType.rw, PDOMappingType.no, od_comparam); + od_comparam.subobjects.Add(3, sub); + //sub = new ODentry("compatibility entry", index, DataType.UNSIGNED8, "0", AccessType.rw, PDOMappingType.no, od_comparam); + //od_comparam.subobjects.Add(4, sub); + sub = new ODentry("event timer", index, DataType.UNSIGNED16, "0", AccessType.rw, PDOMappingType.no, od_comparam); + od_comparam.subobjects.Add(5, sub); + sub = new ODentry("SYNC start value", index, DataType.UNSIGNED8, "0", AccessType.rw, PDOMappingType.no, od_comparam); + od_comparam.subobjects.Add(6, sub); + } + + od_mapping.objecttype = ObjectType.RECORD; + od_mapping.prop.CO_storageGroup = "ROM"; + od_mapping.accesstype = AccessType.rw; //Same as default but inconsistent with ROM above + od_mapping.PDOtype = PDOMappingType.no; + + sub = new ODentry("Number of mapped objects", (UInt16)(index + 0x200), DataType.UNSIGNED8, "0", AccessType.ro, PDOMappingType.no, od_mapping); + od_mapping.subobjects.Add(0, sub); + + for (int p = 1; p <= 8; p++) + { + sub = new ODentry(string.Format("mapped object {0}", p), (UInt16)(index + 0x200), DataType.UNSIGNED32, "0x00000000", AccessType.ro, PDOMappingType.no, od_mapping); + od_mapping.subobjects.Add((byte)p, sub); + } + + ods.Add(index, od_comparam); + ods.Add((UInt16)(index + 0x200), od_mapping); + + return true; + } + + bool CreateTXPDO(UInt16 index) + { + return CreatePDO(false, index); + } + + bool CreateRXPDO(UInt16 index) + { + return CreatePDO(true, index); + } + } +} diff --git a/libEDSsharp/eds.cs b/libEDSsharp/eds.cs index 487acf18..5df21990 100644 --- a/libEDSsharp/eds.cs +++ b/libEDSsharp/eds.cs @@ -331,7 +331,7 @@ public class DcfExport : EdsExport /// /// Section of info in EDS or DCF file /// - public class InfoSection + public partial class InfoSection { protected Dictionary section; @@ -344,24 +344,6 @@ public enum Filetype File_DCF } - public virtual void Parse(Dictionary section,string sectionname) - { - - this.section = section; - - FieldInfo[] fields = this.GetType().GetFields(); - - foreach (FieldInfo f in fields) - { - if(Attribute.IsDefined(f, typeof(EdsExport))) - GetField(f.Name, f.Name); - - if (Attribute.IsDefined(f, typeof(DcfExport))) - GetField(f.Name, f.Name); - } - - } - public bool GetField(string name, string varname) { FieldInfo f = null; @@ -450,51 +432,10 @@ public override string ToString() return msg; } - /// - /// Write object to stream - /// - /// stream to write the data to - /// file type - public void Write(StreamWriter writer, Filetype ft) - { - writer.WriteLine("[" + edssection + "]"); - Type tx = this.GetType(); - FieldInfo[] fields = this.GetType().GetFields(); - - foreach (FieldInfo f in fields) - { - - if ((ft==Filetype.File_EDS) && (!Attribute.IsDefined(f, typeof(EdsExport)))) - continue; - - if ((ft == Filetype.File_DCF) && (!(Attribute.IsDefined(f, typeof(DcfExport)) || Attribute.IsDefined(f, typeof(EdsExport))))) - continue; - - if (f.GetValue(this) == null) - continue; - - EdsExport ex = (EdsExport)f.GetCustomAttribute(typeof(EdsExport)); - - bool comment = ex.IsReadOnly(); - - if (f.FieldType.Name == "Boolean") - { - writer.WriteLine(string.Format("{2}{0}={1}", f.Name, ((bool)f.GetValue(this)) == true ? 1 : 0,comment==true?";":"")); - } - else - { - writer.WriteLine(string.Format("{2}{0}={1}", f.Name, f.GetValue(this).ToString(), comment == true ? ";" : "")); - } - } - - writer.WriteLine(""); - - } - } - public class MandatoryObjects : SupportedObjects + public partial class MandatoryObjects : SupportedObjects { public MandatoryObjects() : base() @@ -502,15 +443,9 @@ public MandatoryObjects() infoheader = "Mandatory Objects"; edssection = "MandatoryObjects"; } - - public MandatoryObjects(Dictionary section) - : this() - { - Parse(section); - } } - public class OptionalObjects : SupportedObjects + public partial class OptionalObjects : SupportedObjects { public OptionalObjects() : base() @@ -518,45 +453,27 @@ public OptionalObjects() infoheader = "Optional Objects"; edssection = "OptionalObjects"; } - - public OptionalObjects(Dictionary section) - : this() - { - Parse(section); - } } - public class ManufacturerObjects : SupportedObjects + public partial class ManufacturerObjects : SupportedObjects { public ManufacturerObjects() : base() { infoheader = "Manufacturer Objects"; edssection = "ManufacturerObjects"; } - - public ManufacturerObjects(Dictionary section) - : this() - { - Parse(section); - } } - public class TypeDefinitions : SupportedObjects + public partial class TypeDefinitions : SupportedObjects { public TypeDefinitions() : base() { infoheader = "Type Definitions"; edssection = "TypeDefinitions"; } - - public TypeDefinitions(Dictionary section) - { - Parse(section); - } - } - public class SupportedObjects + public partial class SupportedObjects { public Dictionary objectlist; @@ -568,23 +485,6 @@ public SupportedObjects() { objectlist = new Dictionary(); } - - public virtual void Parse(Dictionary section) - { - objectlist = new Dictionary(); - foreach(KeyValuePair kvp in section) - { - if(kvp.Key.ToLower()=="supportedobjects") - continue; - - if (kvp.Key.ToLower() == "nrofentries") - continue; - - int count = Convert.ToInt16(kvp.Key, EDSsharp.Getbase(kvp.Key)); - int target = Convert.ToInt16(kvp.Value, EDSsharp.Getbase(kvp.Value)); - objectlist.Add(count, target); - } - } /// /// Returns a string that represents the current object. /// @@ -605,25 +505,9 @@ public override string ToString() return msg; } - /// - /// Write object to stream - /// - /// stream to write the data to - public void Write(StreamWriter writer) - { - writer.WriteLine("[" + edssection + "]"); - writer.WriteLine(string.Format("{0}={1}", countmsg,objectlist.Count)); - foreach (KeyValuePair kvp in objectlist) - { - writer.WriteLine(string.Format("{0}=0x{1:X4}", kvp.Key, kvp.Value)); - } - - writer.WriteLine(""); - } - } - public class Comments + public partial class Comments { public List comments = new List(); @@ -635,23 +519,6 @@ public Comments() } - public Comments(Dictionary section) - { - Parse(section); - } - - public virtual void Parse(Dictionary section) - { - comments = new List(); - foreach (KeyValuePair kvp in section) - { - if (kvp.Key == "Lines") - continue; - - comments.Add(kvp.Value); - - } - } /// /// Returns a string that represents the current object. /// @@ -672,34 +539,10 @@ public override string ToString() return msg; } - /// - /// Write object to stream - /// - /// stream to write the data to - public void Write(StreamWriter writer) - { - if(comments == null) - { - comments = new List(); - } - - writer.WriteLine("[" + edssection + "]"); - - writer.WriteLine(string.Format("Lines={0}", comments.Count)); - - int count = 1; - foreach (string s in comments) - { - writer.WriteLine(string.Format("Line{0}={1}", count, s)); - count++; - } - - writer.WriteLine(""); - } } - public class Dummyusage : InfoSection + public partial class Dummyusage : InfoSection { [EdsExport] public bool Dummy0001; @@ -722,17 +565,12 @@ public Dummyusage() infoheader = "CAN OPEN Dummy Usage"; edssection = "DummyUsage"; } - - public Dummyusage(Dictionary section) : this() - { - Parse(section,edssection); - } } /// /// FileInfo section as described in CiA 306 /// - public class FileInfo : InfoSection + public partial class FileInfo : InfoSection { // Only for internal usage, use Path.GetFileName(eds.projectFilename) instead. /// @@ -805,82 +643,17 @@ public class FileInfo : InfoSection //Folder CO_OD.c and CO_OD.h will be exported into public string exportFolder = ""; - - public FileInfo(Dictionary section) : this() - { - Parse(section,edssection); - } - public FileInfo() { infoheader = "CAN OPEN FileInfo"; edssection = "FileInfo"; } - - - override public void Parse(Dictionary section, string sectionname) - { - - base.Parse(section,edssection); - - string dtcombined = ""; - try - { - if (section.ContainsKey("CreationTime") && section.ContainsKey("CreationDate")) - { - dtcombined = section["CreationTime"].Replace(" ","") + " " + section["CreationDate"]; - CreationDateTime = DateTime.ParseExact(dtcombined, "h:mmtt MM-dd-yyyy", CultureInfo.InvariantCulture); - } - } - catch(Exception e) - { - if (e is System.FormatException) - { - Warnings.warning_list.Add(String.Format("EDS Error: Section [{1}] Unable to parse DateTime {0} for CreationTime, not in DS306 format", dtcombined,sectionname)); - } - } - - try - { - if (section.ContainsKey("ModificationTime") && section.ContainsKey("ModificationTime")) - { - dtcombined = section["ModificationTime"].Replace(" ", "") + " " + section["ModificationDate"]; - ModificationDateTime = DateTime.ParseExact(dtcombined, "h:mmtt MM-dd-yyyy", CultureInfo.InvariantCulture); - } - } - catch (Exception e) - { - if (e is System.FormatException) - { - Warnings.warning_list.Add(String.Format("EDS Error: Section [{1}] Unable to parse DateTime {0} for ModificationTime, not in DS306 format", dtcombined, sectionname)); - } - } - - - try - { - if (section.ContainsKey("EDSVersion")) - { - string[] bits = section["EDSVersion"].Split('.'); - if (bits.Length >= 1) - EDSVersionMajor = Convert.ToByte(bits[0]); - if (bits.Length >= 2) - EDSVersionMinor = Convert.ToByte(bits[1]); - //EDSVersion = String.Format("{0}.{1}", EDSVersionMajor, EDSVersionMinor); - } - } - catch - { - Warnings.warning_list.Add(String.Format("Unable to parse EDS version {0}", section["EDSVersion"])); - } - - } } /// /// DeviceInfo section as described in CiA 306 /// - public class DeviceInfo : InfoSection + public partial class DeviceInfo : InfoSection { /// /// vendor name (max. 244 characters) @@ -1010,15 +783,10 @@ public DeviceInfo() infoheader = "CAN OPEN DeviceInfo"; edssection = "DeviceInfo"; } - - public DeviceInfo(Dictionary section) : this() - { - Parse(section,edssection); - } } - public class DeviceCommissioning : InfoSection + public partial class DeviceCommissioning : InfoSection { public DeviceCommissioning() @@ -1027,11 +795,6 @@ public DeviceCommissioning() edssection = "DeviceComissioning"; } - public DeviceCommissioning(Dictionary section) : this() - { - Parse(section,edssection); - } - [DcfExport] public byte NodeID = 0; @@ -1055,7 +818,7 @@ public DeviceCommissioning(Dictionary section) : this() } - public class SupportedModules : InfoSection + public partial class SupportedModules : InfoSection { [EdsExport] public UInt16 NrOfEntries; @@ -1065,16 +828,9 @@ public SupportedModules() infoheader = "CAN OPEN Supported Modules"; edssection = "SupportedModules"; } - - public SupportedModules(Dictionary section) : this() - { - Parse(section,edssection); - } - - } - public class ConnectedModules : SupportedObjects + public partial class ConnectedModules : SupportedObjects { [EdsExport] public UInt16 NrOfEntries @@ -1091,29 +847,9 @@ public ConnectedModules() countmsg = "NrOfEntries"; connectedmodulelist = new Dictionary(); } - - public ConnectedModules(Dictionary section) : this() - { - Parse(section); - - - foreach(KeyValuePair kvp in this.objectlist) - { - - - UInt16 K = (UInt16)kvp.Value; - UInt16 V = (UInt16)kvp.Key; - - connectedmodulelist.Add(K, V); - - - } - - } - } - public class MxFixedObjects : SupportedObjects + public partial class MxFixedObjects : SupportedObjects { [EdsExport] public UInt16 NrOfEntries @@ -1138,22 +874,9 @@ public MxFixedObjects(UInt16 modindex) countmsg = "NrOfEntries"; connectedmodulelist = new Dictionary(); } - - public MxFixedObjects(Dictionary section, UInt16 modindex) : this(modindex) - { - Parse(section); - - foreach (KeyValuePair kvp in this.objectlist) - { - connectedmodulelist.Add((UInt16)kvp.Value, (UInt16)kvp.Key); - } - } - } - - - public class ModuleInfo : InfoSection + public partial class ModuleInfo : InfoSection { [EdsExport(maxlength = 248)] public string ProductName; @@ -1175,15 +898,9 @@ public ModuleInfo(UInt16 moduleindex) infoheader = "CAN OPEN Module Info " + moduleindex.ToString(); edssection = string.Format("M{0}{1}", moduleindex, "ModuleInfo"); } - - public ModuleInfo(Dictionary section, UInt16 moduleindex) : this (moduleindex) - { - Parse(section,edssection); - } } - - public class ModuleComments : Comments + public partial class ModuleComments : Comments { UInt16 moduleindex; @@ -1194,16 +911,9 @@ public ModuleComments(UInt16 moduleindex) infoheader = "CAN OPEN Module Comments " + moduleindex.ToString(); edssection = string.Format("M{0}{1}", moduleindex, "Comments"); } - - public ModuleComments(Dictionary section,UInt16 moduleindex) : this (moduleindex) - { - Parse(section); - } - - } - public class ModuleSubExtends : SupportedObjects + public partial class ModuleSubExtends : SupportedObjects { UInt16 moduleindex; @@ -1215,18 +925,11 @@ public ModuleSubExtends(UInt16 moduleindex) infoheader = "CAN OPEN ModuleSubExtends "+moduleindex.ToString(); edssection = string.Format("M{0}{1}", moduleindex, "SubExtends"); } - - public ModuleSubExtends(Dictionary section, UInt16 moduleindex) - : this(moduleindex) - { - Parse(section); - } - } /// /// Represent object dictionary index and subindex objects /// - public class ODentry + public partial class ODentry { private UInt16 _index; @@ -1711,112 +1414,6 @@ public string Formatoctetstring(string value) return ret; } - /// - /// Write out this Object dictionary entry to an EDS/DCF file using correct formatting - /// - /// Handle to the stream writer to write to - /// File type being written - /// OD type to write - /// module - public void Write(StreamWriter writer, InfoSection.Filetype ft, Odtype odt= Odtype.NORMAL, int module=0) - { - - string fixedmodheader = ""; - - if (odt == Odtype.FIXED) - { - fixedmodheader = string.Format("M{0}Fixed", module); - } - - if(odt == Odtype.SUBEXT) - { - fixedmodheader = string.Format("M{0}SubExt", module); - } - - if (parent != null) - { - writer.WriteLine(string.Format("[{0}{1:X}sub{2:X}]", fixedmodheader,Index, Subindex)); - } - else - { - writer.WriteLine(string.Format("[{0}{1:X}]",fixedmodheader,Index)); - } - - writer.WriteLine(string.Format("ParameterName={0}", parameter_name)); - - if(ft == InfoSection.Filetype.File_DCF) - { - writer.WriteLine(string.Format("Denotation={0}", denotation)); - } - - writer.WriteLine(string.Format("ObjectType=0x{0:X}", (int)objecttype)); - writer.WriteLine(string.Format(";StorageLocation={0}", prop.CO_storageGroup)); - - if (objecttype == ObjectType.ARRAY) - { - writer.WriteLine(string.Format("SubNumber=0x{0:X}", Nosubindexes)); - } - - if (objecttype == ObjectType.RECORD) - { - writer.WriteLine(string.Format("SubNumber=0x{0:X}", Nosubindexes)); - } - - if (objecttype == ObjectType.VAR) - { - DataType dt = datatype; - if (dt == DataType.UNKNOWN && this.parent != null) - dt = parent.datatype; - writer.WriteLine(string.Format("DataType=0x{0:X4}", (int)dt)); - writer.WriteLine(string.Format("AccessType={0}", accesstype.ToString())); - - - if(HighLimit != null && HighLimit != "") - { - writer.WriteLine(string.Format("HighLimit={0}", Formatoctetstring(HighLimit))); - } - - if (LowLimit != null && LowLimit != "") - { - writer.WriteLine(string.Format("LowLimit={0}", Formatoctetstring(LowLimit))); - } - - writer.WriteLine(string.Format("DefaultValue={0}", Formatoctetstring(defaultvalue))); - - //TODO If the ObjectType is domain (0x2) the value of the object may be stored in a file,UploadFile and DownloadFile - if (ft == InfoSection.Filetype.File_DCF) - { - writer.WriteLine(string.Format("ParameterValue={0}", Formatoctetstring(actualvalue))); - } - - writer.WriteLine(string.Format("PDOMapping={0}", PDOMapping==true?1:0)); - - if (prop.CO_flagsPDO == true) - { - writer.WriteLine(";TPDODetectCos=1"); - } - - - } - - //Count is for modules in the [MxSubExtxxxx] - //Should we export this on EDS only, or DCF or both? - if (odt == Odtype.SUBEXT ) - { - writer.WriteLine(string.Format("Count={0}", count)); - writer.WriteLine(string.Format("ObjExtend={0}", ObjExtend)); - } - - //ObjectFlags is always optional (Page 15, DSP306) and used for DCF writing to nodes - //also recommended not to write if it is already 0 - if (ObjFlags != 0) - { - writer.WriteLine(string.Format("ObjFlags={0}", ObjFlags)); - } - - writer.WriteLine(""); - } - /// /// Returns a c compatible string that represents the name of the object, - is replaced with _ /// words separated by a space are replaced with _ for a separator eg ONE TWO becomes ONE_TWO @@ -2069,7 +1666,7 @@ public Module(UInt16 moduleindex) } - public class EDSsharp + public partial class EDSsharp { public enum AccessType @@ -2281,829 +1878,19 @@ public List VerifyPDOMapping() return mappingErrors; } - public void Parseline(string linex,int no) + public DataType Getdatatype(ODentry od) { - string key = ""; - string value = ""; - - string line = linex.TrimStart(';'); - bool custom_extension = false; - - if (linex == null || linex == "") - return; - - if (linex[0] == ';') - custom_extension = true; - - - //extract sections + if (od.objecttype == ObjectType.VAR) { - string pat = @"^\[([a-z0-9]+)\]"; - - Regex r = new Regex(pat, RegexOptions.IgnoreCase); - Match m = r.Match(line); - if (m.Success) - { - Group g = m.Groups[1]; - sectionname = g.ToString(); - - if (!eds.ContainsKey(sectionname)) - { - eds.Add(sectionname, new Dictionary()); - } - else - { - Warnings.warning_list.Add(string.Format("EDS Error on Line {0} : Duplicate section [{1}] ", no,sectionname)); - } - } + return od.datatype; } - //extract keyvalues + if (od.objecttype == ObjectType.ARRAY) { - //Bug #70 Eat whitespace! - string pat = @"^([a-z0-9_]+)[ ]*=[ ]*(.*)"; + ODentry sub2 = ods[od.Index]; - Regex r = new Regex(pat, RegexOptions.IgnoreCase); - Match m = r.Match(line); - if (m.Success) - { - key = m.Groups[1].ToString(); - value = m.Groups[2].ToString(); - value = value.TrimEnd(' ','\t','\n','\r'); - - //not sure how we actually get here with out a section being in the dictionary already.. - //suspect this is dead code. - if (!eds.ContainsKey(sectionname)) - { - eds.Add(sectionname, new Dictionary()); - } - - if (custom_extension == false) - { - try - { - eds[sectionname].Add(key, value); - } - catch(Exception) - { - Warnings.warning_list.Add(string.Format("EDS Error on Line {3} : Duplicate key \"{0}\" value \"{1}\" in section [{2}]", key,value,sectionname, no)); - } - } - else - //Only allow our own extensions to populate the key/value pair - { - if (key == "StorageLocation" || key== "TPDODetectCos") - { - try - { - eds[sectionname].Add(key, value); - } - catch(Exception) - { - Warnings.warning_list.Add(string.Format("EDS Error on Line {3} : Duplicate custom key \"{0}\" value \"{1}\" in section [{2}]", key, value, sectionname, no)); - } - } - } - } - } - } - - public void ParseEDSentry(KeyValuePair> kvp) - { - string section = kvp.Key; - - string pat = @"^(M[0-9a-fA-F]+(Fixed|SubExt))?([a-fA-F0-9]+)(sub)?([0-9a-fA-F]*)$"; - - Regex r = new Regex(pat); - Match m = r.Match(section); - if (m.Success) - { - - SortedDictionary target = this.ods; - - //** MODULE DCF SUPPORT - - string pat2 = @"^M([0-9a-fA-F]+)(Fixed|SubExt)([0-9a-fA-F]+)"; - Regex r2 = new Regex(pat2, RegexOptions.IgnoreCase); - Match m2 = r2.Match(m.Groups[0].ToString()); - - if (m2.Success) - { - UInt16 modindex=0, odindex=0; - - try { modindex = Convert.ToUInt16(m2.Groups[1].Value); } - catch (Exception) { Console.WriteLine("** ALL GONE WRONG **" + m2.Groups[1].Value); } - //Indexes in the EDS are always in hex format without the pre 0x - try { odindex = Convert.ToUInt16(m2.Groups[3].Value, 16); } - catch (Exception) { Console.WriteLine("** ALL GONE WRONG **" + m2.Groups[3].Value); } - - - if (!modules.ContainsKey(modindex)) - modules.Add(modindex, new Module(modindex)); - - if (m2.Groups[2].ToString() == "SubExt") - { - target = modules[modindex].modulesubext; - - } - else - { - target = modules[modindex].modulefixedobjects; - } - } - - - ODentry od = new ODentry - { - //Indexes in the EDS are always in hex format without the pre 0x - Index = Convert.ToUInt16(m.Groups[3].ToString(), 16) - }; - - //Parameter name, mandatory always - if (!kvp.Value.ContainsKey("ParameterName")) - throw new ParameterException("Missing required field ParameterName on" + section); - od.parameter_name = kvp.Value["ParameterName"]; - - //Object type, assumed to be VAR unless specified - if (kvp.Value.ContainsKey("ObjectType")) - { - int type = Convert.ToInt16(kvp.Value["ObjectType"], Getbase(kvp.Value["ObjectType"])); - od.objecttype = (ObjectType)type; - } - else - { - od.objecttype = ObjectType.VAR; - } - - if(kvp.Value.ContainsKey("CompactSubObj")) - { - od.CompactSubObj = Convert.ToByte(kvp.Value["CompactSubObj"],Getbase(kvp.Value["CompactSubObj"])); - } - - if(kvp.Value.ContainsKey("ObjFlags")) - { - od.ObjFlags = Convert.ToUInt32(kvp.Value["ObjFlags"], Getbase(kvp.Value["ObjFlags"])); - } - else - { - od.ObjFlags = 0; - } - - //Access Type - if(kvp.Value.ContainsKey("StorageLocation")) - { - od.prop.CO_storageGroup = kvp.Value["StorageLocation"]; - } - - if (kvp.Value.ContainsKey("TPDODetectCos")) - { - string test = kvp.Value["TPDODetectCos"].ToLower(); - if (test == "1" || test == "true") - { - od.prop.CO_flagsPDO = true; - } - else - od.prop.CO_flagsPDO = false; - } - - if (kvp.Value.ContainsKey("Count")) - { - /* FIXME: The format of "Count" is Unsigned8[; Unsigned8] according DS306 - * Count: - Number of extended Sub-Indexes with this description that are created per module. The format is Unsigned8 [; Unsigned8]. - If one or more Sub - Indexes are created per attached module to build a new sub- index, then Count is that Number. In example 32 bit module creates 4 Sub - Indexes each having 8 Bit: Count = 4 - If several modules are gathered to form a new Sub- Index, then the number is 0, followed by semicolon and the number of bits that are created per module to build a new Sub-Index.In example 2 bit modules with 8 bit objects: The first Sub - Index is built upon modules 1 - 4, the next upon modules 5 - 8 etc.: Count = 0; 2.The objects are created, when a new byte begins: Module 1 creates the Sub - Index 1; modules 2 - 4 fill it up; module 5 creates Sub-Index 2 and so forth. - */ - pat2 = @"\s*([0-9a-fA-F]+)\s*;\s*([0-9a-fA-F]+)"; - r2 = new Regex(pat2, RegexOptions.IgnoreCase); - m2 = r2.Match(kvp.Value["Count"]); - - - - if (m2.Success) - { - Console.WriteLine("** FIXME Count format not supported ** Count: " + kvp.Value["Count"]); - int found = kvp.Value["Count"].IndexOf(";"); - string s = kvp.Value["Count"].Substring(found + 1); - try { od.count = Convert.ToByte(s, Getbase(s)); } - catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** Count" + kvp.Value["Count"]); } - } - else - { - - try { od.count = Convert.ToByte(kvp.Value["Count"], Getbase(kvp.Value["Count"])); } - catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** Count" + kvp.Value["Count"]); } - } - - } - - if (kvp.Value.ContainsKey("ObjExtend")) - { - try { od.ObjExtend = Convert.ToByte(kvp.Value["ObjExtend"]); } - catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** ObjExtend:" + kvp.Value["ObjExtend"]); } - - } - - - if (od.objecttype == ObjectType.VAR) - { - - if (kvp.Value.ContainsKey("CompactSubObj")) - throw new ParameterException("CompactSubObj not valid for a VAR Object, section: " + section); - - if (kvp.Value.ContainsKey("ParameterValue")) - { - - try { od.actualvalue = kvp.Value["ParameterValue"]; } - catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** ParameterValue:" + kvp.Value["ParameterValue"]); } - } - - if (kvp.Value.ContainsKey("HighLimit")) - { - try { od.HighLimit = kvp.Value["HighLimit"]; } - catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** HighLimit:" + kvp.Value["HighLimit"]); } - } - - if (kvp.Value.ContainsKey("LowLimit")) - { - try { od.LowLimit = kvp.Value["LowLimit"]; } - catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** LowLimit:" + kvp.Value["LowLimit"]); } - } - - if (kvp.Value.ContainsKey("Denotation")) - { - try { od.denotation = kvp.Value["Denotation"]; } - catch (Exception) { Console.WriteLine("** ALL GONE WRONG ** Denotation:" + kvp.Value["Denotation"]); } - - - } - - if (m.Groups[5].Length != 0) - { - //FIXME are subindexes in hex always? - UInt16 subindex = Convert.ToUInt16(m.Groups[5].ToString(),16); - od.parent = target[od.Index]; - target[od.Index].subobjects.Add(subindex, od); - } - - if (!kvp.Value.ContainsKey("DataType")) - throw new ParameterException("Missing required field DataType on" + section); - od.datatype = (DataType)Convert.ToInt16(kvp.Value["DataType"], Getbase(kvp.Value["DataType"])); - - if (!kvp.Value.ContainsKey("AccessType")) - throw new ParameterException("Missing required AccessType on" + section); - - string accesstype = kvp.Value["AccessType"].ToLower(); - - if (Enum.IsDefined(typeof(AccessType), accesstype)) - { - od.accesstype = (AccessType)Enum.Parse(typeof(AccessType), accesstype); - } - else - { - throw new ParameterException("Unknown AccessType on" + section); - } - - if (kvp.Value.ContainsKey("DefaultValue")) - od.defaultvalue = kvp.Value["DefaultValue"]; - - od.PDOtype = PDOMappingType.no; - if (kvp.Value.ContainsKey("PDOMapping")) - { - - bool pdo = Convert.ToInt16(kvp.Value["PDOMapping"],Getbase(kvp.Value["PDOMapping"])) == 1; - if (pdo == true) - od.PDOtype = PDOMappingType.optional; - } - - } - - - if(od.objecttype == ObjectType.RECORD|| od.objecttype == ObjectType.ARRAY || od.objecttype == ObjectType.DEFSTRUCT) - { - - if (od.CompactSubObj != 0) - { - if (!kvp.Value.ContainsKey("DataType")) - throw new ParameterException("Missing required field DataType on" + section); - od.datatype = (DataType)Convert.ToInt16(kvp.Value["DataType"], Getbase(kvp.Value["DataType"])); - - if (!kvp.Value.ContainsKey("AccessType")) - throw new ParameterException("Missing required AccessType on" + section); - string accesstype = kvp.Value["AccessType"]; - if (Enum.IsDefined(typeof(AccessType), accesstype)) - { - od.accesstype = (AccessType)Enum.Parse(typeof(AccessType), accesstype); - } - else - { - throw new ParameterException("Unknown AccessType on" + section); - } - - //now we generate CompactSubObj number of var objects below this parent - - if(od.CompactSubObj>=0xfe) - { - od.CompactSubObj = 0xfe; - } - - ODentry subi = new ODentry("NrOfObjects", od.Index, DataType.UNSIGNED8, String.Format("0x{0:x2}",od.CompactSubObj), AccessType.ro, PDOMappingType.no, od); - od.subobjects.Add(0x00, subi); - - for (int x=1; x<= od.CompactSubObj; x++) - { - string parameter_name = string.Format("{0}{1:x2}", od.parameter_name, x ); - ODentry sub = new ODentry(parameter_name, od.Index, od.datatype, od.defaultvalue, od.accesstype, od.PDOtype, od); - - if (kvp.Value.ContainsKey("HighLimit")) - sub.HighLimit = kvp.Value["HighLimit"]; - - if (kvp.Value.ContainsKey("LowLimit")) - sub.HighLimit = kvp.Value["LowLimit"]; - - od.subobjects.Add((ushort)(x ), sub); - } - - } - else - { - if (!kvp.Value.ContainsKey("SubNumber")) - throw new ParameterException("Missing SubNumber on Array for" + section); - - - - } - } - - if(od.objecttype == ObjectType.DOMAIN) - { - od.datatype = DataType.DOMAIN; - od.accesstype = AccessType.rw; - - if (kvp.Value.ContainsKey("DefaultValue")) - od.defaultvalue = kvp.Value["DefaultValue"]; - - } - - //Only add top level to this list - if (m.Groups[5].Length == 0) - { - target.Add(od.Index, od); - } - } - - } - - public void Loadfile(string filename) - { - - projectFilename = filename; - - if (Path.GetExtension(filename).ToLower() == ".eds") - { - edsfilename = filename; - } - - if (Path.GetExtension(filename).ToLower() == ".dcf") - { - dcffilename = filename; - } - - //try - { - int lineno = 1; - foreach (string linex in System.IO.File.ReadLines(filename)) - { - Parseline(linex,lineno); - lineno++; - } - - di = new DeviceInfo(eds["DeviceInfo"]); - - foreach (KeyValuePair> kvp in eds) - { - - try { ParseEDSentry(kvp); } - catch (Exception) { Console.WriteLine("** ALL GONE WRONG **" + kvp); } - - } - - fi = new FileInfo(eds["FileInfo"]); - if(eds.ContainsKey("DummyUsage")) - du = new Dummyusage(eds["DummyUsage"]); - - md = new MandatoryObjects(eds["MandatoryObjects"]); - - if(eds.ContainsKey("OptionalObjects")) - oo = new OptionalObjects(eds["OptionalObjects"]); - - if(eds.ContainsKey("ManufacturerObjects")) - mo = new ManufacturerObjects(eds["ManufacturerObjects"]); - - if (eds.ContainsKey("TypeDefinitions")) - td = new TypeDefinitions(eds["TypeDefinitions"]); - - //Only DCF not EDS files - dc = new DeviceCommissioning(); - string strSection = ""; - if (eds.ContainsKey("DeviceCommissioning")) // wrong section name as defined in the DSP302, but right spelling (for compabiltiy to some tools) - strSection = "DeviceCommissioning"; - else if (eds.ContainsKey("DeviceComissioning")) // right section name as defined in the DSP302, (wrong spelling) - strSection = "DeviceComissioning"; - - if (strSection != ""){ - dc.Parse(eds[strSection],"DeviceCommissioning"); - edsfilename = fi.LastEDS; - } - - c = new Comments(); - - if (eds.ContainsKey("Comments")) - c.Parse(eds["Comments"]); - - //Modules - - //FIXME - //we don't parse or support [MxFixedObjects] with MxFixedxxxx and MxFixedxxxxsubx - - if (eds.ContainsKey("SupportedModules")) - { - sm = new SupportedModules(eds["SupportedModules"]); - - //find MxModuleInfo - - foreach (string s in eds.Keys) - { - String pat = @"M([0-9]+)ModuleInfo"; - Regex r = new Regex(pat, RegexOptions.IgnoreCase); - Match m = r.Match(s); - - if (m.Success) - { - UInt16 modindex = Convert.ToUInt16(m.Groups[1].Value); - ModuleInfo mi = new ModuleInfo(eds[s], modindex); - - if (!modules.ContainsKey(modindex)) - modules.Add(modindex, new Module(modindex)); - - modules[modindex].mi = mi; - - } - - - pat = @"M([0-9]+)Comments"; - r = new Regex(pat, RegexOptions.IgnoreCase); - m = r.Match(s); - - if (m.Success) - { - UInt16 modindex = Convert.ToUInt16(m.Groups[1].Value); - ModuleComments mc = new ModuleComments(eds[s], modindex); - - if (!modules.ContainsKey(modindex)) - modules.Add(modindex, new Module(modindex)); - - modules[modindex].mc = mc; - - } - pat = @"M([0-9]+)SubExtends"; - r = new Regex(pat, RegexOptions.IgnoreCase); - m = r.Match(s); - - if (m.Success) - { - UInt16 modindex = Convert.ToUInt16(m.Groups[1].Value); - ModuleSubExtends mse = new ModuleSubExtends(eds[s], modindex); - - if (!modules.ContainsKey(modindex)) - modules.Add(modindex, new Module(modindex)); - - modules[modindex].mse = mse; - } - - - //DCF only - - pat = @"M([0-9]+)FixedObjects"; - r = new Regex(pat, RegexOptions.IgnoreCase); - m = r.Match(s); - - if (m.Success) - { - UInt16 modindex = Convert.ToUInt16(m.Groups[1].Value); - MxFixedObjects mxf = new MxFixedObjects(eds[s],modindex); - - if (!modules.ContainsKey(modindex)) - modules.Add(modindex, new Module(modindex)); - - modules[modindex].mxfo = mxf; - - } - } - } - - - if (eds.ContainsKey("ConnectedModules")) - { - cm = new ConnectedModules(eds["ConnectedModules"]); - } - - //COMPACT PDO - - if (di.CompactPDO != 0) - { - - for (UInt16 index = 0x1400; index < 0x1600; index++) - { - ApplycompactPDO(index); - } - - for (UInt16 index = 0x1800; index < 0x1A00;index ++) - { - ApplycompactPDO(index); - } - } - - ApplyimplicitPDO(); - } - // catch(Exception e) - //{ - // Console.WriteLine("** ALL GONE WRONG **" + e.ToString()); - // } - } - - public void ApplycompactPDO(UInt16 index) - { - if (ods.ContainsKey(index)) - { - if ((!ods[index].Containssubindex(1)) && ((this.di.CompactPDO & 0x01) == 0)) - { - //Fill in cob ID - //FIX ME i'm really sure this is not correct, what default values should be used??? - string cob = string.Format("$NODEID + 0x180"); - ODentry subod = new ODentry("COB-ID", index, DataType.UNSIGNED32, cob, AccessType.rw, PDOMappingType.no, ods[index]); - ods[index].subobjects.Add(0x05, subod); - - } - - if ((!ods[index].Containssubindex(2)) && ((this.di.CompactPDO & 0x02) == 0)) - { - //Fill in type - - ODentry subod = new ODentry("Type", index, DataType.UNSIGNED8, "0xff", AccessType.rw, PDOMappingType.no, ods[index]); - ods[index].subobjects.Add(0x02, subod); - } - - if ((!ods[index].Containssubindex(3)) && ((this.di.CompactPDO & 0x04) == 0)) - { - //Fill in inhibit - - ODentry subod = new ODentry("Inhibit time", index, DataType.UNSIGNED16, "0", AccessType.rw, PDOMappingType.no, ods[index]); - ods[index].subobjects.Add(0x03, subod); - } - - //NOT FOR RX PDO - if (index < 0x1800) - return; - - if ((!ods[index].Containssubindex(4)) && ((this.di.CompactPDO & 0x08) == 0)) - { - //Fill in compatibility entry - - ODentry subod = new ODentry("Compatibility entry", index, DataType.UNSIGNED8, "0", AccessType.ro, PDOMappingType.no, ods[index]); - ods[index].subobjects.Add(0x04, subod); - } - - if ((!ods[index].Containssubindex(5)) && ((this.di.CompactPDO & 0x10) == 0)) - { - //Fill in event timer - - ODentry subod = new ODentry("Event Timer", index, DataType.UNSIGNED16, "0", AccessType.rw, PDOMappingType.no, ods[index]); - ods[index].subobjects.Add(0x05, subod); - } - } - } - - /// - /// This function scans the PDO list and compares it to NrOfRXPDO and NrOfTXPDO - /// if these do not match in count then implicit PDOs are present and they are - /// filled in with default values from the lowest possible index - /// - public void ApplyimplicitPDO() - { - UInt16 totalnorxpdos = di.NrOfRXPDO; - UInt16 totalnotxpdos = di.NrOfTXPDO; - - UpdatePDOcount(); - - UInt16 noexplicitrxpdos = di.NrOfRXPDO; - UInt16 noexplicittxpdos = di.NrOfTXPDO; - - //this is how many PDOS need generating on the fly - UInt16 noimplictrxpdos = (UInt16) (totalnorxpdos - noexplicitrxpdos); - UInt16 noimplicttxpdos = (UInt16) (totalnotxpdos - noexplicittxpdos); - - for(UInt16 index = 0x1400; (index < 0x1600) && (noimplictrxpdos > 0) ;index++) - { - if(!ods.ContainsKey(index)) - { - CreateRXPDO(index); - noimplictrxpdos--; - } - } - - for (UInt16 index = 0x1800; (index < 0x1A00) && (noimplicttxpdos > 0); index++) - { - if (!ods.ContainsKey(index)) - { - CreateTXPDO(index); - noimplicttxpdos--; - } - } - - UpdatePDOcount(); - - } - - public void Savefile(string filename, InfoSection.Filetype ft) - { - if(ft==InfoSection.Filetype.File_EDS) - this.edsfilename = filename; - - if (ft == InfoSection.Filetype.File_DCF) - { - this.dcffilename = filename; - fi.LastEDS = edsfilename; - } - - UpdatePDOcount(); - - //generate date times in DS306 format; h:mmtt MM-dd-yyyy - - fi.CreationDate = fi.CreationDateTime.ToString("MM-dd-yyyy", CultureInfo.InvariantCulture); - fi.CreationTime = fi.CreationDateTime.ToString("h:mmtt", CultureInfo.InvariantCulture); - - fi.ModificationDate = fi.ModificationDateTime.ToString("MM-dd-yyyy", CultureInfo.InvariantCulture); - fi.ModificationTime = fi.ModificationDateTime.ToString("h:mmtt", CultureInfo.InvariantCulture); - - fi.FileName = Path.GetFileName(filename); - - fi.EDSVersion = "4.0"; - fi.EDSVersionMajor = 4; - fi.EDSVersionMinor = 0; - - StreamWriter writer = System.IO.File.CreateText(filename); - writer.NewLine = "\n"; - fi.Write(writer,ft); - di.Write(writer,ft); - du.Write(writer,ft); - c.Write(writer); - - if(ft == InfoSection.Filetype.File_DCF) - { - dc.Write(writer,ft); - } - - //regenerate the object lists - md.objectlist.Clear(); - mo.objectlist.Clear(); - oo.objectlist.Clear(); - - foreach (KeyValuePair kvp in ods) - { - ODentry entry = kvp.Value; - - if (entry.prop.CO_disabled == true) - continue; - - if (entry.Index == 0x1000 || entry.Index == 0x1001 || entry.Index == 0x1018) - { - md.objectlist.Add(md.objectlist.Count + 1, entry.Index); - } - else - if (entry.Index >= 0x2000 && entry.Index < 0x6000) - { - mo.objectlist.Add(mo.objectlist.Count + 1, entry.Index); - } - else - { - oo.objectlist.Add(oo.objectlist.Count + 1, entry.Index); - } - } - - md.Write(writer); - - foreach (KeyValuePair kvp in ods) - { - ODentry od = kvp.Value; - if (md.objectlist.ContainsValue(od.Index)) - { - od.Write(writer,ft); - foreach (KeyValuePair kvp2 in od.subobjects) - { - ODentry od2 = kvp2.Value; - od2.Write(writer,ft); - } - } - } - - oo.Write(writer); - - foreach (KeyValuePair kvp in ods) - { - ODentry od = kvp.Value; - if (oo.objectlist.ContainsValue(od.Index)) - { - od.Write(writer,ft); - foreach (KeyValuePair kvp2 in od.subobjects) - { - ODentry od2 = kvp2.Value; - od2.Write(writer,ft); - } - } - } - - mo.Write(writer); - - foreach (KeyValuePair kvp in ods) - { - ODentry od = kvp.Value; - if (mo.objectlist.ContainsValue(od.Index)) - { - od.Write(writer,ft); - foreach (KeyValuePair kvp2 in od.subobjects) - { - ODentry od2 = kvp2.Value; - od2.Write(writer,ft); - } - } - } - - //modules - - if (sm.NrOfEntries > 0) - { - sm.Write(writer, ft); - - for (UInt16 moduleid = 1; moduleid <= sm.NrOfEntries; moduleid++) - { - - modules[moduleid].mi.Write(writer, ft); - - modules[moduleid].mc.Write(writer); - - modules[moduleid].mse.Write(writer); - - - foreach (KeyValuePair kvp2 in modules[moduleid].modulesubext) - { - ODentry od = kvp2.Value; - od.Write(writer, ft, ODentry.Odtype.SUBEXT, moduleid); - - } - - modules[moduleid].mxfo.Write(writer); - - foreach (KeyValuePair kvp3 in modules[moduleid].modulefixedobjects) - { - ODentry od = kvp3.Value; - od.Write(writer, ft, ODentry.Odtype.SUBEXT, moduleid); - - foreach (KeyValuePair kvp4 in od.subobjects) - { - ODentry subod = kvp4.Value; - subod.Write(writer, ft, ODentry.Odtype.FIXED, moduleid); - } - } - } - } - - if (ft == InfoSection.Filetype.File_DCF) - { - if (cm.NrOfEntries > 0) - { - cm.Write(writer); - } - } - - writer.Close(); - - } - - public DataType Getdatatype(ODentry od) - { - - if (od.objecttype == ObjectType.VAR) - { - return od.datatype; - } - - if (od.objecttype == ObjectType.ARRAY) - { - ODentry sub2 = ods[od.Index]; - - //FIX ME !!! INCONSISTANT setup of the datatype for arrays when loading xml and eds!! + //FIX ME !!! INCONSISTANT setup of the datatype for arrays when loading xml and eds!! DataType t = sub2.datatype; @@ -3304,178 +2091,6 @@ public bool tryGetODEntry(UInt16 index, out ODentry od) return false; } - //RX COM 0x1400 - //RX Map 0x1600 - //TX COM 0x1800 - //TX MAP 0x1a00 - - //call this with the comm param index not the mapping - public bool CreatePDO(bool rx,UInt16 index) - { - //check if we are creating an RX PDO it is a valid index - if (rx && (index < 0x1400 || index >= 0x1600)) - return false; - - //check if we are creating an PDO TX it is a valid index - if (!rx & (index < 0x1800 || index >= 0x1A00)) - return false; - - //Check it does not already exist - if (ods.ContainsKey(index)) - return false; - - //check the associated mapping index does not exist - if (ods.ContainsKey((UInt16)(index+0x200))) - return false; - - ODentry od_comparam; - ODentry od_mapping; - - if (rx) - { - od_comparam = new ODentry("RPDO communication parameter", index, 0) - { - Description = @"0x1400 - 0x15FF RPDO communication parameter -max sub-index - -COB - ID - bit 0 - 10: COB - ID for PDO, to change it bit 31 must be set - bit 11 - 29: set to 0 for 11 bit COB - ID - bit 30: 0(1) - rtr are allowed(are NOT allowed) for PDO - bit 31: 0(1) - node uses(does NOT use) PDO - -Transmission type - value = 0 - 240: receiving is synchronous, process after next reception of SYNC object - value = 241 - 253: not used - value = 254: manufacturer specific - value = 255: asynchronous" - }; - - od_mapping = new ODentry("RPDO mapping parameter", (UInt16)(index + 0x200), 0) - { - Description = @"0x1600 - 0x17FF RPDO mapping parameter (To change mapping, 'Number of mapped objects' must be set to 0) -Number of mapped objects - -mapped object (subindex 1...8) - bit 0 - 7: data length in bits - bit 8 - 15: subindex from OD - bit 16 - 31: index from OD" - }; - - - } - else - { - od_comparam = new ODentry("TPDO communication parameter", index, 0) - { - Description = @"0x1800 - 0x19FF TPDO communication parameter -max sub-index - -COB - ID - bit 0 - 10: COB - ID for PDO, to change it bit 31 must be set - bit 11 - 29: set to 0 for 11 bit COB - ID - bit 30: 0(1) - rtr are allowed(are NOT allowed) for PDO - bit 31: 0(1) - node uses(does NOT use) PDO - -Transmission type - value = 0: transmitting is synchronous, specification in device profile - value = 1 - 240: transmitting is synchronous after every N - th SYNC object - value = 241 - 251: not used - value = 252 - 253: Transmitted only on reception of Remote Transmission Request - value = 254: manufacturer specific - value = 255: asynchronous, specification in device profile - -inhibit time - bit 0 - 15: Minimum time between transmissions of the PDO in 100µs.Zero disables functionality. - -event timer - bit 0-15: Time between periodic transmissions of the PDO in ms.Zero disables functionality. - -SYNC start value - value = 0: Counter of the SYNC message shall not be processed. - value = 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message." - }; - - - od_mapping = new ODentry("TPDO mapping parameter", (UInt16)(index + 0x200), 0) - { - Description = @"0x1A00 - 0x1BFF TPDO mapping parameter. (To change mapping, 'Number of mapped objects' must be set to 0). -Number of mapped objects - -mapped object (subindex 1...8) - bit 0 - 7: data length in bits - bit 8 - 15: subindex from OD - bit 16 - 31: index from OD" - }; - } - - od_comparam.objecttype = ObjectType.RECORD; - od_comparam.prop.CO_storageGroup = "ROM"; - od_comparam.accesstype = AccessType.ro; - od_comparam.PDOtype = PDOMappingType.no; - - ODentry sub; - - - if(rx) - { - sub = new ODentry("max sub-index", index, DataType.UNSIGNED8, "2", AccessType.ro, PDOMappingType.no, od_comparam); - od_comparam.subobjects.Add(0, sub); - sub = new ODentry("COB-ID used by RPDO", index, DataType.UNSIGNED32, "$NODEID+0x200", AccessType.rw, PDOMappingType.no, od_comparam); - od_comparam.subobjects.Add(1, sub); - sub = new ODentry("transmission type", index, DataType.UNSIGNED8, "254", AccessType.rw, PDOMappingType.no, od_comparam); - od_comparam.subobjects.Add(2, sub); - - } - else - { - sub = new ODentry("max sub-index", index, DataType.UNSIGNED8, "6", AccessType.ro, PDOMappingType.no, od_comparam); - od_comparam.subobjects.Add(0, sub); - sub = new ODentry("COB-ID used by TPDO", index, DataType.UNSIGNED32, "$NODEID+0x180", AccessType.rw, PDOMappingType.no, od_comparam); - od_comparam.subobjects.Add(1, sub); - sub = new ODentry("transmission type", index, DataType.UNSIGNED8, "254", AccessType.rw, PDOMappingType.no, od_comparam); - od_comparam.subobjects.Add(2, sub); - sub = new ODentry("inhibit time", index, DataType.UNSIGNED16, "0", AccessType.rw, PDOMappingType.no, od_comparam); - od_comparam.subobjects.Add(3, sub); - //sub = new ODentry("compatibility entry", index, DataType.UNSIGNED8, "0", AccessType.rw, PDOMappingType.no, od_comparam); - //od_comparam.subobjects.Add(4, sub); - sub = new ODentry("event timer", index, DataType.UNSIGNED16, "0", AccessType.rw, PDOMappingType.no, od_comparam); - od_comparam.subobjects.Add(5, sub); - sub = new ODentry("SYNC start value", index, DataType.UNSIGNED8, "0", AccessType.rw, PDOMappingType.no, od_comparam); - od_comparam.subobjects.Add(6, sub); - - } - - od_mapping.objecttype = ObjectType.RECORD; - od_mapping.prop.CO_storageGroup = "ROM"; - od_mapping.accesstype = AccessType.rw; //Same as default but inconsistent with ROM above - od_mapping.PDOtype = PDOMappingType.no; - - sub = new ODentry("Number of mapped objects", (UInt16)(index + 0x200), DataType.UNSIGNED8, "0", AccessType.ro, PDOMappingType.no, od_mapping); - od_mapping.subobjects.Add(0, sub); - - for (int p=1;p<=8;p++) - { - sub = new ODentry(string.Format("mapped object {0}",p), (UInt16)(index+0x200), DataType.UNSIGNED32, "0x00000000", AccessType.ro, PDOMappingType.no, od_mapping); - od_mapping.subobjects.Add((byte)p, sub); - } - - ods.Add(index, od_comparam); - ods.Add((UInt16)(index + 0x200), od_mapping); - - return true; - } - - public bool CreateTXPDO(UInt16 index) - { - return CreatePDO(false, index); - } - - public bool CreateRXPDO(UInt16 index) - { - return CreatePDO(true, index); - } - public ODentry Getobject(UInt16 no) {