diff --git a/.gitignore b/.gitignore index 2a48e46..dbb5e11 100644 --- a/.gitignore +++ b/.gitignore @@ -365,4 +365,6 @@ FodyWeavers.xsd *.so -*.o \ No newline at end of file +*.o + +*.csproj.user \ No newline at end of file diff --git a/libconnection b/libconnection index 0e4de4a..77d6ef6 160000 --- a/libconnection +++ b/libconnection @@ -1 +1 @@ -Subproject commit 0e4de4a5cfafec76095f4b19f425f64967fdef2b +Subproject commit 77d6ef6b6614b7f68a4b63fe69d0f024f09a6380 diff --git a/libxcm/.gitignore b/libxcm/.gitignore index 4c26367..dbb5e11 100644 --- a/libxcm/.gitignore +++ b/libxcm/.gitignore @@ -1,3 +1,5 @@ +*/Properties/ + ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## @@ -363,4 +365,6 @@ FodyWeavers.xsd *.so -*.o \ No newline at end of file +*.o + +*.csproj.user \ No newline at end of file diff --git a/libxcm/AggregateMessage.cs b/libxcm/AggregateMessage.cs new file mode 100644 index 0000000..2388811 --- /dev/null +++ b/libxcm/AggregateMessage.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace libxcm +{ + internal class AggregateMessage + { + } +} diff --git a/libxcm/BigIntegerConverter.cs b/libxcm/BigIntegerConverter.cs new file mode 100644 index 0000000..0565bd9 --- /dev/null +++ b/libxcm/BigIntegerConverter.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace libxcm +{ + public class BigIntegerConverter : JsonConverter + { + public override BigInteger Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.Number) + throw new JsonException(string.Format("Found token {0} but expected token {1}", reader.TokenType, JsonTokenType.Number)); + using var doc = JsonDocument.ParseValue(ref reader); + return BigInteger.Parse(doc.RootElement.GetRawText(), NumberFormatInfo.InvariantInfo); + } + + public override void Write(Utf8JsonWriter writer, BigInteger value, JsonSerializerOptions options) + { + var s = value.ToString(NumberFormatInfo.InvariantInfo); + using var doc = JsonDocument.Parse(s); + doc.WriteTo(writer); + } + } +} diff --git a/libxcm/CSVConverter.cs b/libxcm/CSVConverter.cs new file mode 100644 index 0000000..c012580 --- /dev/null +++ b/libxcm/CSVConverter.cs @@ -0,0 +1,34 @@ +using libxcm; +using System.Text; +using System.Text.Json; +using libxcm.JsonTypes; +using System.Collections.Generic; +using System.IO; + +namespace xcmparser +{ + class CsvConverter : IMessageFormatter + { + public void SendConvertedMessage(libconnection.Pipe pipe, Message msg) + { + foreach (Symbol symbol in msg) + { + using MemoryStream memorystream = new(); + string symbolbasename = msg.Name; + if(!symbol.IsAnonymous) + { + symbolbasename += "_" + symbol.Name; + } + StreamWriter sr = new(memorystream); + sr.Write(symbolbasename + ";"); + foreach (Entry entry in symbol) + { + sr.Write(entry.GetValue().ToString() + ";"); + } + sr.WriteLine(); + string csvline = Encoding.ASCII.GetString(memorystream.ToArray()); + pipe.TransmitMessage(new libconnection.Message(csvline)); + } + } + } +} \ No newline at end of file diff --git a/libxcm/Command.cs b/libxcm/Command.cs index 3c588c5..4707bb9 100644 --- a/libxcm/Command.cs +++ b/libxcm/Command.cs @@ -7,11 +7,11 @@ namespace libxcm { public class Command : Message { - public Command(XmlNode commandNode, List knownSymbols) : base(commandNode, knownSymbols) + public Command(XmlNode commandNode, InboundConnection inbound, OutboundConnection outbound, string systemName) : base(commandNode, inbound, outbound, systemName) { } - protected Command(XmlNode commandNode, List knownSymbols, Func symbolFactory, Func EntryFactory) : base(commandNode, knownSymbols, symbolFactory, EntryFactory) + protected Command(XmlNode commandNode, Func symbolFactory, Func EntryFactory, InboundConnection inbound, OutboundConnection outbound) : base(commandNode, symbolFactory, EntryFactory, inbound, outbound) { } } diff --git a/libxcm/Entry.cs b/libxcm/Entry.cs index 6ce66e1..e7df7c0 100644 --- a/libxcm/Entry.cs +++ b/libxcm/Entry.cs @@ -20,10 +20,12 @@ public Entry(XmlNode entryNode) if (entryNode.Attributes["name"] == null) { Name = "AnonymousEntry"; + IsAnonymous = true; } else { Name = entryNode.Attributes["name"].Value; + IsAnonymous = false; } if (entryNode.Attributes["visibility"] != null && entryNode.Attributes["visibility"].Value == "virtual") @@ -53,19 +55,6 @@ public Entry(XmlNode entryNode) IsFixedCommand = entryNode.Attributes["fixed"].Value.ToLower() == "true"; } - if(entryNode.Attributes["importand"] != null) - { - IsImportand = entryNode.Attributes["importand"].Value.ToLower() == "true"; - } - - string checkString = null; - if (entryNode.Attributes["check"] != null) - { - checkString = entryNode.Attributes["check"].Value; - IsImportand = true; - IsChecked = true; - } - switch (type.ToLower()) { case "int": @@ -79,11 +68,6 @@ public Entry(XmlNode entryNode) { Value.SetValue(valueString); } - CheckValue = new FixedNumber(bitlength, true); - if (checkString != null) - { - CheckValue.SetValue(checkString); - } break; case "uint": BaseType = "fixed"; @@ -96,11 +80,6 @@ public Entry(XmlNode entryNode) { Value.SetValue(valueString); } - CheckValue = new FixedNumber(bitlength, false); - if (checkString != null) - { - CheckValue.SetValue(checkString); - } break; case "bool": BaseType = "bool"; @@ -123,11 +102,6 @@ public Entry(XmlNode entryNode) { Value.SetValue(valueString); } - CheckValue = new Bool(); - if (checkString != null) - { - CheckValue.SetValue(checkString); - } break; case "double": BaseType = "double"; @@ -136,11 +110,6 @@ public Entry(XmlNode entryNode) { Value.SetValue(valueString); } - CheckValue = new FloatingPointNumber(FloatingPointType.@double); - if (checkString != null) - { - CheckValue.SetValue(checkString); - } break; case "float": BaseType = "float"; @@ -149,11 +118,6 @@ public Entry(XmlNode entryNode) { Value.SetValue(valueString); } - CheckValue = new FloatingPointNumber(FloatingPointType.@float); - if (checkString != null) - { - CheckValue.SetValue(checkString); - } break; case "string": BaseType = "string"; @@ -212,6 +176,8 @@ public Entry(XmlNode entryNode) public bool IsVisible { get; protected set; } = true; + public bool IsAnonymous { get; protected set; } = false; + public IType Value { get; set; } public T GetValue() @@ -237,21 +203,6 @@ public bool TryGetValue(ref T value) } } - public IType CheckValue { get; set; } - - public bool IsImportand { get; set; } = false; - - public bool IsChecked { get; set; } = false; - - public bool CheckValueForCorrectness() - { - if(IsChecked && Value != null && CheckValue != null) - { - return Value.Equals(CheckValue); - } - return true; - } - public int MaxBitLength { get diff --git a/libxcm/IMessageFormatter.cs b/libxcm/IMessageFormatter.cs new file mode 100644 index 0000000..9ab24d6 --- /dev/null +++ b/libxcm/IMessageFormatter.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using libconnection; +using libconnection.Packetizer; + +namespace libxcm +{ + public interface IMessageFormatter + { + public void SendConvertedMessage(Pipe pipe, Message msg); + } +} diff --git a/libxcm/ISystemFactory.cs b/libxcm/ISystemFactory.cs new file mode 100644 index 0000000..2f9c84a --- /dev/null +++ b/libxcm/ISystemFactory.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace libxcm +{ + public interface ISystemFactory + { + public XCMSystem BuildSystem(XmlNode node, Dictionary inboundconnections, Dictionary outboundconnections); + public ITokenFactory GetTokenFactory(); + } +} diff --git a/libxcm/ITokenFactory.cs b/libxcm/ITokenFactory.cs new file mode 100644 index 0000000..ae950fa --- /dev/null +++ b/libxcm/ITokenFactory.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace libxcm +{ + public interface ITokenFactory + { + public Message BuildMessage(XmlNode node, InboundConnection inbound, OutboundConnection outbound, string systemName); + public Command BuildCommand(XmlNode node, InboundConnection inbound, OutboundConnection outbound, string systemName); + public Symbol BuildSymbol(XmlNode node); + } +} diff --git a/libxcm/InboundConnection.cs b/libxcm/InboundConnection.cs new file mode 100644 index 0000000..bea251c --- /dev/null +++ b/libxcm/InboundConnection.cs @@ -0,0 +1,77 @@ +using libconnection; +using libconnection.DataProzessor; +using libconnection.Interfaces; +using libconnection.Packetizer; +using System; +using System.Collections.Generic; +using System.Xml; + +namespace libxcm +{ + public class InboundConnection : Pipe + { + static private readonly MessageConverterNameResolver nameResolver = MessageConverterNameResolver.Instance; + + public static T BuildConnectionPartByNode(XmlElement node) + { + Dictionary parameters = new(); + foreach (XmlNode parameter in node) + { + if (parameter.Name.ToLower() == "parameter") + { + string parameterName = parameter.Attributes["name"]?.Value; + if (string.IsNullOrWhiteSpace(parameterName)) + { + throw new ArgumentException("The connection node must have a name attribute."); + } + parameters.Add(parameterName, parameter.InnerText); + } + } + var className = ((XmlElement)node).GetAttribute("class"); + if (string.IsNullOrWhiteSpace(className)) + { + throw new ArgumentException("Each connection node must have a classname assigned"); + } + if(typeof(T) == typeof(IInterface)) + { + return (T)nameResolver.GetInterfaceByName(className, parameters); + } + else if(typeof(T) == typeof(IPacketizer)) + { + return (T)nameResolver.GetPacketizerByName(className, parameters); + } + else if(typeof(T) == typeof(IDataProcessor)) + { + return (T)nameResolver.GetProcessorByName(className, parameters); + } + else + { + throw new ArgumentException(); + } + } + + public InboundConnection(XmlNode node, IDictionary ifaces) : base() + { + foreach (XmlNode stage in node) + { + if(stage.NodeType != XmlNodeType.Comment) + { + switch(stage.Name.ToLower()) + { + case "interface": + string ifaceName = stage.InnerText; + AddInterface(ifaces[ifaceName]); + break; + case "packetizer": + AddPacketizer(BuildConnectionPartByNode((XmlElement)stage)); + break; + case "processor": + break; + case "filter": + break; + } + } + } + } + } +} diff --git a/libxcm/JsonConverter.cs b/libxcm/JsonConverter.cs new file mode 100644 index 0000000..7ca1858 --- /dev/null +++ b/libxcm/JsonConverter.cs @@ -0,0 +1,120 @@ +using libxcm; +using libxcm.JsonTypes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace xcmparser +{ + public class JsonConverter : IMessageFormatter + { + private static object SymbolToTagedObject(Symbol symb) + { + Dictionary tags = new Dictionary(); + foreach (Entry entry in symb) + { + var val = EntryToExtendedJSON(entry); + string name = entry.Name; + tags.Add(name, val); + } + return new + { + value = tags, + isEntry = false, + isSymbol = true + }; + } + + public static byte[] ConvertDataToJSONByte(Message msg, ref string msgName, IDictionary additionalFields) + { + return Encoding.UTF8.GetBytes(ConvertDataToJSON(msg, ref msgName, additionalFields)); + } + + public static object EntryToExtendedJSON(Entry entry) + { + return new + { + value = entry.GetValue() + }; + } + public static string ConvertDataToJSON(Message msg, ref string msgName, IDictionary additionalFields, bool pretty = false) + { + Dictionary tags = new Dictionary(); + foreach (Symbol symbol in msg) + { + string name = symbol.Name; + if (string.IsNullOrWhiteSpace(name)) + { + foreach (Entry entry in symbol) + { + tags.Add(entry.Name, EntryToExtendedJSON(entry)); + } + } + else + { + tags.Add(name, SymbolToTagedObject(symbol)); + } + } + JsonSerializerOptions options = new JsonSerializerOptions(); + options.Converters.Add(new BigIntegerConverter()); + options.WriteIndented = pretty; + msgName = msg.Name; + return JsonSerializer.Serialize(new + { + msg.SystemName, + Type = "receiveddata", + MessageName = msg.Name, + Fields = tags, + Custom = additionalFields + }, options) + "\n"; + } + + public byte[] ConvertToByteArray(Message msg) + { + string dummy = string.Empty; + return ConvertDataToJSONByte(msg, ref dummy, null); + } + + public byte[] ConvertToByteArray(Message msg, out object additionalData) + { + string name = string.Empty; + additionalData = null; + var output = ConvertDataToJSONByte(msg, ref name, null); + if (!string.IsNullOrWhiteSpace(name)) + { + additionalData = name; + } + return output; + } + + public static void GetDataFromJson(IEnumerable data, Command com) + { + GetDataFromJson(data as byte[] ?? data.ToArray(), com); + } + + public static void GetDataFromJson(byte[] data, Command com) + { + var str = Encoding.UTF8.GetString(data); + GetDataFromJson(str, com); + } + + public static void GetDataFromJson(string json, Command com) + { + var jsoncommand = JsonSerializer.Deserialize(json); + jsoncommand?.FillCommand(com); + } + + public void SendConvertedMessage(libconnection.Pipe pipe, Message msg) + { + var data = ConvertToByteArray(msg, out object additionalData); + var convertedMsg = new libconnection.Message(data) + { + CustomObject = additionalData + }; + pipe.TransmitMessage(convertedMsg); + } + } +} diff --git a/libxcm/JsonTypes/JsonCommand.cs b/libxcm/JsonTypes/JsonCommand.cs new file mode 100644 index 0000000..fd37bd7 --- /dev/null +++ b/libxcm/JsonTypes/JsonCommand.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace libxcm.JsonTypes +{ + internal class JsonCommand + { + public JsonSymbol[] Fields { get; set; } = new JsonSymbol[0]; + public string Type { get; set; } + public string Name { get; set; } + + public void FillCommand(Command command) + { + if(Type.ToLower() == "sendcommand" && Name.ToLower() == command.Name.ToLower()) + { + foreach (var symbol in command) + { + if (symbol.IsAnonymous) + { + + foreach (var element in Fields.TakeWhile(x => x.IsAnonymous).SelectMany(x => x.Elements)) + { + var entry = symbol.FindEntry(element.Name); + if (entry != null) + { + element.FillEntry(entry); + } + } + } + else + { + Fields.TakeWhile(x => x.Name.ToLower() == symbol.Name.ToLower()).First()?.FillSymbol(symbol); + } + } + } + } + } +} diff --git a/libxcm/JsonTypes/JsonElement.cs b/libxcm/JsonTypes/JsonElement.cs new file mode 100644 index 0000000..d4f2d14 --- /dev/null +++ b/libxcm/JsonTypes/JsonElement.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace libxcm.JsonTypes +{ + internal class JsonElement + { + public object value { get; set; } = null; + public string Name { get; set; } + + public void FillEntry(Entry entry) + { + entry.Value.SetValue(((System.Text.Json.JsonElement)value).GetRawText()); + } + } +} diff --git a/libxcm/JsonTypes/JsonSymbol.cs b/libxcm/JsonTypes/JsonSymbol.cs new file mode 100644 index 0000000..86db1dc --- /dev/null +++ b/libxcm/JsonTypes/JsonSymbol.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace libxcm.JsonTypes +{ + internal class JsonSymbol + { + public JsonElement[] Elements { get; set; } = new JsonElement[0]; + public string Name { get; set; } + + public bool IsAnonymous => Name?.ToLower().Contains("anonymous") ?? true; + + public void FillSymbol(Symbol symbol) + { + foreach(var entry in symbol) + { + Elements.TakeWhile(x => x.Name.ToLower() == entry.Name.ToLower()).First()?.FillEntry(entry); + } + } + } +} diff --git a/libxcm/Message.cs b/libxcm/Message.cs index 2029c46..4ffbeb5 100644 --- a/libxcm/Message.cs +++ b/libxcm/Message.cs @@ -12,6 +12,8 @@ public class Message : IEnumerable { protected readonly byte[] identifier; protected readonly List symbols = new List(); + protected readonly InboundConnection inbound; + protected readonly OutboundConnection outbound; public int IDOffset { get; protected set; } = 0; private int idlength = -1; @@ -26,13 +28,18 @@ private static Entry EntryFactory(XmlNode entryNode) return new Entry(entryNode); } - public Message(XmlNode messageNode, List knownSymbols) : this(messageNode, knownSymbols, SymbolFactory, EntryFactory) + public string SystemName{get;set;} + + public Message(XmlNode messageNode, InboundConnection inbound, OutboundConnection outbound, string systemName) : this(messageNode, SymbolFactory, EntryFactory, inbound, outbound) { - + SystemName = systemName; } - protected Message(XmlNode messageNode, List knownSymbols, Func symbolFactory, Func EntryFactory) + protected Message(XmlNode messageNode, Func symbolFactory, Func EntryFactory, InboundConnection inbound, OutboundConnection outbound) { + this.inbound = inbound; + this.outbound = outbound; + bool isString; identifier = GetIdentifierData(messageNode, out isString); IdentifierIsString = isString; @@ -45,6 +52,10 @@ protected Message(XmlNode messageNode, List knownSymbols, Func knownSymbols, Func x.Name == symbolRef) ?? throw new ArgumentException("ref doesn't point to a defined symbol")).Copy(); if (symbolNode.Attributes["name"] != null) @@ -68,7 +80,7 @@ protected Message(XmlNode messageNode, List knownSymbols, Func knownSymbols, Func DocuText { get; set; } = new List(); public bool IdentifierIsString { get; protected set; } = false; @@ -125,7 +139,7 @@ public static byte[] GetHex(string hex) foreach (string token in tokenized) { int value = Convert.ToInt32(token, 16); - id.Insert(0, (byte)value); + id.Add((byte)value); } } catch(FormatException) @@ -175,6 +189,7 @@ public Func,bool> GetMatchFunction() public virtual bool Match(IEnumerable data) { + /* bool groupmatched = true; if(Group != null) { @@ -183,7 +198,8 @@ public virtual bool Match(IEnumerable data) } groupmatched = groupmatched && data.Take(identifier.Length).SequenceEqual(identifier); - return groupmatched; + return groupmatched;*/ + return data.Take(identifier.Length).SequenceEqual(identifier); } public int GetBitlength() diff --git a/libxcm/MessageConverterNameResolver.cs b/libxcm/MessageConverterNameResolver.cs new file mode 100644 index 0000000..707bd15 --- /dev/null +++ b/libxcm/MessageConverterNameResolver.cs @@ -0,0 +1,71 @@ +using libconnection; +using libconnection.Packetizer; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace libxcm +{ + public class MessageConverterNameResolver : NameResolver + { + private static MessageConverterNameResolver instance = null; + private static readonly object padlock = new(); + private readonly Dictionary formatterClasses = new(); + public static new MessageConverterNameResolver Instance + { + get + { + lock (padlock) + { + if (instance == null) + { + instance = new MessageConverterNameResolver(); + return instance; + } + return instance; + } + } + } + + protected MessageConverterNameResolver() : base() + { + LoadOutputFormatters(typeof(MessageConverterNameResolver).Assembly); + } + + public void LoadOutputFormatters(Assembly assy) + { + foreach (var type in assy.GetTypes()) + { + if (type.GetCustomAttribute(typeof(OutputFormatterAttribute)) is OutputFormatterAttribute attribute) + { + if (!formatterClasses.TryAdd(attribute.GetClassName(), type)) + { + var originalType = formatterClasses[attribute.GetClassName()]; + throw new ArgumentException($"Multiple Interfaces with the same name: {attribute.GetClassName()} in {type.FullName} and {originalType.FullName}"); + } + } + } + } + + public IMessageFormatter GeFormatterByName(string name, IDictionary initialization) + { + if (formatterClasses.TryGetValue(name.ToLower(), out Type itype)) + { + var method = itype.GetMethod("GenerateWithParameters"); + if (method != null) + { + return method.Invoke(null, new IDictionary[] { initialization }) as IMessageFormatter; + } + else + { + var constructor = itype.GetConstructor(Type.EmptyTypes); + return constructor.Invoke(null) as IMessageFormatter; + } + } + return null; + } + } +} diff --git a/libxcm/MessageGroup.cs b/libxcm/MessageGroup.cs index 2d67435..7704ff7 100644 --- a/libxcm/MessageGroup.cs +++ b/libxcm/MessageGroup.cs @@ -8,6 +8,7 @@ namespace libxcm { public class MessageGroup { + /* protected readonly byte[] identifier; public MessageGroup(XmlNode groupNode, List knownSymbols, XCMTokenizer tokenizer) { @@ -54,5 +55,6 @@ public bool DataMatch(IEnumerable data) } public MessageGroup Group = null; + */ } } diff --git a/libxcm/MqttJsonConverter.cs b/libxcm/MqttJsonConverter.cs new file mode 100644 index 0000000..783846a --- /dev/null +++ b/libxcm/MqttJsonConverter.cs @@ -0,0 +1,78 @@ +using libxcm; +using System.Text; +using System.Text.Json; +using libxcm.JsonTypes; +using System.Collections.Generic; +using libconnection; +using System.Linq; + +namespace xcmparser +{ + [OutputFormatter("mqtt")] + class MqttJsonConverter : IMessageFormatter + { + public static MqttJsonConverter GenerateWithParameters(IDictionary parameter) + { + bool splitMessage = true; + if (parameter.ContainsKey("splitmessage")) + { + splitMessage = parameter["splitmessage"].ToLower() == "true"; + } + + var tags = parameter.Where(x => x.Key.StartsWith("tag-")).ToDictionary(dict => dict.Key.Split("-").Last(), dict => dict.Value); + + return new MqttJsonConverter() + { + SplitMessages = splitMessage + , Tags = tags + }; + } + public bool SplitMessages { get; set; } = true; + public Dictionary Tags { get; set; } = new(); + private static void AddTag(ref string topic, string tag) + { + topic += "_" + tag; + } + + public void SendConvertedMessage(libconnection.Pipe pipe, libxcm.Message msg) + { + string mqttTopic = $"{msg.SystemName}/{msg.Name}"; + if (SplitMessages) + { + foreach (Symbol symbol in msg) + { + foreach (Entry entry in symbol) + { + if (!symbol.IsAnonymous) + { + AddTag(ref mqttTopic, symbol.Name); + } + AddTag(ref mqttTopic, entry.Name); + string json = JsonSerializer.Serialize(new + { + value = entry.GetValue() + }); + pipe.TransmitMessage(new libconnection.Message(json) + { + CustomObject = mqttTopic + }); + } + } + } + else + { + string messageName = msg.Name; + var bytes = JsonConverter.ConvertDataToJSONByte(msg, ref messageName, Tags); + pipe.TransmitMessage(new libconnection.Message(bytes) + { + CustomObject = mqttTopic + }); + } + } + + public IEnumerable Decode(IEnumerable data) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/libxcm/OutboundConnection.cs b/libxcm/OutboundConnection.cs new file mode 100644 index 0000000..7d09c80 --- /dev/null +++ b/libxcm/OutboundConnection.cs @@ -0,0 +1,63 @@ +using libconnection; +using libconnection.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace libxcm +{ + public class OutboundConnection : InboundConnection + { + private static readonly MessageConverterNameResolver nameresolver = MessageConverterNameResolver.Instance; + + public static new T BuildConnectionPartByNode(XmlElement node) + { + Dictionary parameters = new(); + foreach (XmlNode parameter in node) + { + if (parameter.Name.ToLower() == "parameter") + { + string parameterName = parameter.Attributes["name"]?.Value; + if (string.IsNullOrWhiteSpace(parameterName)) + { + throw new ArgumentException("The connection node must have a name attribute."); + } + parameters.Add(parameterName, parameter.InnerText); + } + } + var className = ((XmlElement)node).GetAttribute("name"); + if (string.IsNullOrWhiteSpace(className)) + { + throw new ArgumentException("A formatter must be selected with a unique name"); + } + + if (typeof(T) == typeof(IMessageFormatter)) + { + return (T)nameresolver.GeFormatterByName(className, parameters); + } + else + { + return InboundConnection.BuildConnectionPartByNode(node); + } + } + + public OutboundConnection(XmlNode node, IDictionary ifaces) : base(node, ifaces) + { + var outformatNode = node.SelectSingleNode("outputformat"); + if(outformatNode != null) + { + MessageConverter = BuildConnectionPartByNode((XmlElement)outformatNode); + } + } + + public IMessageFormatter MessageConverter { get; set; } = new xcmparser.JsonConverter(); + + public void TransmitParsedData(Message msg) + { + MessageConverter.SendConvertedMessage(this, msg); + } + } +} diff --git a/libxcm/OutputFormatterAttribute.cs b/libxcm/OutputFormatterAttribute.cs new file mode 100644 index 0000000..d643a5f --- /dev/null +++ b/libxcm/OutputFormatterAttribute.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace libxcm +{ + [AttributeUsage(AttributeTargets.Class)] + internal class OutputFormatterAttribute : Attribute + { + private string className; + + public OutputFormatterAttribute(string className) + { + this.className = className; + } + public string GetClassName() + { + return className; + } + } +} diff --git a/libxcm/System.cs b/libxcm/System.cs new file mode 100644 index 0000000..17f00c8 --- /dev/null +++ b/libxcm/System.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace libxcm +{ + public class XCMSystem + { + protected readonly ITokenFactory factory; + protected Dictionary> compiledtokens = new Dictionary>(); + protected List knownSymbols = new List(); + protected InboundConnection inbound; + protected OutboundConnection outbound; + public XCMSystem(XmlNode root, ITokenFactory factory, Dictionary inboundConnections, Dictionary outboundConnections) + { + this.factory = factory; + Name = root.Attributes["name"]?.Value ?? ""; + inbound = GetInboundConnectionFromXML(root, inboundConnections); + outbound = GetOutboundConnectionFromXML(root, outboundConnections); + if (inbound == null || outbound == null) + { + throw new ArgumentException("The system must have one inbound and outbound connection"); + } + foreach (XmlNode token in root) + { + if (token.NodeType != XmlNodeType.Comment) + { + foreach (XmlNode t in token) + { + if (t.NodeType != XmlNodeType.Comment) + { + BuildToken(token, t, Name); + } + } + } + } + } + + void BuildToken(XmlNode parent, XmlNode node, string systemName) + { + switch (node.Name.ToLower()) + { + /* + case "symbol": + if (!compiledtokens.ContainsKey("symbol")) + { + compiledtokens.Add("symbol", new List()); + } + Symbol symb = factory.BuildSymbol(node); + compiledtokens["symbol"].Add(symb); + knownSymbols.Add(symb); + break; + */ + case "message": + if (!compiledtokens.ContainsKey("message")) + { + compiledtokens.Add("message", new List()); + } + compiledtokens["message"].Add(factory.BuildMessage(node, inbound, outbound, systemName)); + break; + case "command": + if (!compiledtokens.ContainsKey("command")) + { + compiledtokens.Add("command", new List()); + } + compiledtokens["command"].Add(factory.BuildCommand(node, inbound, outbound, systemName)); + break; + /* + case "Group": + MessageGroup group = BuildGroup(node); + foreach(Message msg in group.Messages) + { + compiledtokens["message"].Add(msg); + } + break;*/ + default: + break; + } + } + + private static InboundConnection GetInboundConnectionFromXML(XmlNode node, Dictionary connections) + { + var defInput = node.SelectSingleNode("defaultInput"); + if (defInput == null) return null; + var connName = defInput.InnerText; + if (connections.TryGetValue(connName, out InboundConnection value)) return value; + else + { + return null; + } + } + + private static OutboundConnection GetOutboundConnectionFromXML(XmlNode node, Dictionary connections) + { + var defInput = node.SelectSingleNode("defaultOutput"); + if (defInput == null) return null; + var connName = defInput.InnerText; + if (connections.TryGetValue(connName, out OutboundConnection value)) return value; + else + { + return null; + } + } + + public IEnumerable GetObjects(bool strict = true) + { + foreach (var t in compiledtokens) + { + foreach (object obj in t.Value) + { + if (strict) + { + if (obj.GetType() == typeof(T)) + { + yield return (T)obj; + } + } + else + { + if (obj is T val) + { + yield return val; + } + } + } + } + } + + public string Name { get; set; } + } +} diff --git a/libxcm/SystemFactory.cs b/libxcm/SystemFactory.cs new file mode 100644 index 0000000..7e65de4 --- /dev/null +++ b/libxcm/SystemFactory.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace libxcm +{ + public class SystemFactory : ISystemFactory, ITokenFactory + { + private readonly ITokenFactory tokenfactory; + + public SystemFactory() + { + tokenfactory = this; + } + public SystemFactory(ITokenFactory tokenfactory) + { + this.tokenfactory = tokenfactory; + } + + public Command BuildCommand(XmlNode node, InboundConnection inbound, OutboundConnection outbound, string systemName) + { + return new Command(node, inbound, outbound, systemName); + } + + public Message BuildMessage(XmlNode node, InboundConnection inbound, OutboundConnection outbound, string systemName) + { + return new Message(node, inbound, outbound, systemName); + } + + public Symbol BuildSymbol(XmlNode node) + { + return new Symbol(node); + } + + public XCMSystem BuildSystem(XmlNode node, Dictionary inboundconnections, Dictionary outboundconnections) + { + return new XCMSystem(node, tokenfactory, inboundconnections, outboundconnections); + } + + public ITokenFactory GetTokenFactory() + { + return tokenfactory; + } + } +} diff --git a/libxcm/XCMDokument.cs b/libxcm/XCMDokument.cs new file mode 100644 index 0000000..948e494 --- /dev/null +++ b/libxcm/XCMDokument.cs @@ -0,0 +1,109 @@ +using libconnection; +using libconnection.Interfaces; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Xml; + +namespace libxcm +{ + public class XCMDokument + { + private readonly Dictionary systems = new (); + + private readonly Dictionary incommingConnections = new(); + private readonly Dictionary outgoingConnections = new(); + + private readonly Dictionary interfaces = new (); + + + public XCMDokument(XmlDocument doc, ISystemFactory factory) : this(doc.DocumentElement, factory) + { + + } + + public XCMDokument(XmlElement root, ISystemFactory factory) + { + foreach (XmlElement ifaceNode in root.SelectNodes("/systems/interfaces/interface")) + { + var ifaceName = ifaceNode.GetAttribute("name"); + if (string.IsNullOrWhiteSpace(ifaceName)) + { + throw new ArgumentException("Each interface element must have a name"); + } + if (interfaces.ContainsKey(ifaceName)) + { + throw new ArgumentException("Each interface element must have a unique name"); + } + interfaces.Add(ifaceName, InboundConnection.BuildConnectionPartByNode(ifaceNode)); + } + + + foreach (XmlElement incon in root.SelectNodes("/systems/connections/incomming/connection")) //Read all incomming connections and generate connection elements from it + { + string connName = incon.GetAttribute("name"); + if(string.IsNullOrWhiteSpace(connName)) + { + throw new ArgumentException("Each connection element must have a name"); + } + if(incommingConnections.ContainsKey(connName)) + { + throw new ArgumentException("Each connection element must have a unique name"); + } + var connection = new InboundConnection(incon, interfaces); + incommingConnections.Add(connName, connection); + } + + foreach (XmlElement outcon in root.SelectNodes("/systems/connections/outgoing/connection")) //Read all outgoing connections and generate connection elements from it + { + string connName = outcon.GetAttribute("name"); + if (string.IsNullOrWhiteSpace(connName)) + { + throw new ArgumentException("Each connection element must have a name"); + } + if (outgoingConnections.ContainsKey(connName)) + { + throw new ArgumentException("Each connection element must have a unique name"); + } + var connection = new OutboundConnection(outcon, interfaces); + outgoingConnections.Add(connName, connection); + } + + foreach (XmlElement systemNode in root.SelectNodes("/systems/system")) + { + string systemname = systemNode.Attributes["name"].Value; + if (systemname == null || systems.ContainsKey(systemname)) + throw new ArgumentException("A system must have a unique name"); + var system = factory.BuildSystem(systemNode, incommingConnections, outgoingConnections); + systems.Add(systemname, system); + } + } + + public async Task StartConnectionsAsync(CancellationToken token) + { + List tasks = new(); + foreach(var connection in incommingConnections.Values) + { + tasks.Add(connection.StartPipeAsync(token)); + } + foreach (var connection in outgoingConnections.Values) + { + tasks.Add(connection.StartPipeAsync(token)); + } + + await Task.WhenAll(tasks); + } + + public IEnumerable GetTokenizers() + { + return systems.Values; + } + + public XCMSystem GetTokenzierByName(string name) + { + return systems[name]; + } + } +} diff --git a/libxcm/XCMTokenizer.cs b/libxcm/XCMTokenizer.cs deleted file mode 100644 index 11d5adb..0000000 --- a/libxcm/XCMTokenizer.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Xml; -using System.Linq; - -namespace libxcm -{ - public class XCMTokenizer - { - protected Dictionary> compiledtokens = new Dictionary>(); - protected List knownSymbols = new List(); - public XCMTokenizer(XmlDocument doc) : this(doc.DocumentElement, new XmlNamespaceManager(doc.NameTable)) - { - - } - public XCMTokenizer(XmlElement root, XmlNamespaceManager mngr) - { - mngr.AddNamespace("sps", "http://www.w3schools.com/"); - foreach(XmlNode token in root) - { - foreach(XmlNode t in token) - { - if(t.NodeType != XmlNodeType.Comment) - { - BuildToken(token, t); - } - } - } - } - - public IEnumerable GetObjects(bool strict = true) - { - foreach(var t in compiledtokens) - { - foreach(object obj in t.Value) - { - if (strict) - { - if (obj.GetType() == typeof(T)) - { - yield return (T)obj; - } - } - else - { - if (obj is T val) - { - yield return val; - } - } - } - } - } - - virtual public Message BuildMessage(XmlNode node) - { - return new Message(node, knownSymbols); - } - - virtual public Command BuildCommand(XmlNode node) - { - return new Command(node, knownSymbols); - } - - virtual public Symbol BuildSymbol(XmlNode node) - { - return new Symbol(node); - } - - virtual public MessageGroup BuildGroup(XmlNode node) - { - return new MessageGroup(node, knownSymbols, this); - } - virtual protected void BuildToken(XmlNode parent, XmlNode node) - { - switch(node.Name.ToLower()) - { - case "symbol": - if(!compiledtokens.ContainsKey("symbol")) - { - compiledtokens.Add("symbol", new List()); - } - Symbol symb = BuildSymbol(node); - compiledtokens["symbol"].Add(symb); - knownSymbols.Add(symb); - break; - case "message": - if (!compiledtokens.ContainsKey("message")) - { - compiledtokens.Add("message", new List()); - } - compiledtokens["message"].Add(BuildMessage(node)); - break; - case "command": - if (!compiledtokens.ContainsKey("command")) - { - compiledtokens.Add("command", new List()); - } - compiledtokens["command"].Add(BuildCommand(node)); - break; - case "Group": - MessageGroup group = BuildGroup(node); - foreach(Message msg in group.Messages) - { - compiledtokens["message"].Add(msg); - } - break; - default: - break; - } - } - } -} diff --git a/libxcm/libxcm.csproj b/libxcm/libxcm.csproj index dbdcea4..7cec651 100644 --- a/libxcm/libxcm.csproj +++ b/libxcm/libxcm.csproj @@ -1,7 +1,11 @@  - netstandard2.0 + net7.0 + + + + diff --git a/libxcmparse/.gitignore b/libxcmparse/.gitignore index 4c26367..dbb5e11 100644 --- a/libxcmparse/.gitignore +++ b/libxcmparse/.gitignore @@ -1,3 +1,5 @@ +*/Properties/ + ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## @@ -363,4 +365,6 @@ FodyWeavers.xsd *.so -*.o \ No newline at end of file +*.o + +*.csproj.user \ No newline at end of file diff --git a/libxcmparse/DataObjects/DataCommand.cs b/libxcmparse/DataObjects/DataCommand.cs index 3e014e9..f688038 100644 --- a/libxcmparse/DataObjects/DataCommand.cs +++ b/libxcmparse/DataObjects/DataCommand.cs @@ -2,21 +2,19 @@ using System; using System.Collections.Generic; using System.Text; +using System.Text.Json.Serialization; using System.Xml; namespace libxcmparse.DataObjects { public class DataCommand : Command { - public static Command CommandFactory(XmlNode messageNode, List knownSymbols) - { - return new DataCommand(messageNode, knownSymbols); - } - public DataCommand(XmlNode commandNode, List knownSymbols) : this(commandNode, knownSymbols, DataMessage.SymbolFactory, DataMessage.EntryFactory) + public DataCommand(XmlNode commandNode, InboundConnection inbound, OutboundConnection outbound, string systemName) : this(commandNode, DataMessage.SymbolFactory, DataMessage.EntryFactory, inbound, outbound) { + SystemName = systemName; } - protected DataCommand(XmlNode commandNode, List knownSymbols, Func symbolFactory, Func EntryFactory) : base(commandNode, knownSymbols, symbolFactory, EntryFactory) + protected DataCommand(XmlNode commandNode, Func symbolFactory, Func EntryFactory, InboundConnection inbound, OutboundConnection outbound) : base(commandNode, symbolFactory, EntryFactory, inbound, outbound) { List sibblings = new List(); foreach (DataSymbol symb in this) @@ -27,6 +25,15 @@ protected DataCommand(XmlNode commandNode, List knownSymbols, Func()); + IsValid = (bool)validExpr.Evaluate(); + } + catch(InvalidCastException) + { + throw new XmlException($"Error in Element {entryNode.OuterXml}\n Invalid ValidExpression in {Name} found. Expression must return a boolean"); + } + break; + case "warning": + HasChecks = true; + try + { + warningExpr = new Expression(childNode.FirstChild.Value); + warningExpr.Parameters.Add("value", GetValue()); + HasWarning = (bool)warningExpr.Evaluate(); + } + catch (InvalidCastException) + { + throw new XmlException($"Error in Element {entryNode.OuterXml}\n Invalid WarningExpression in {Name} found. Expression must return a boolean"); + } + break; } } } @@ -224,11 +252,16 @@ private void RollArray(IType[] arr) public string Unit { get; private set; } = ""; + public bool IsValid { get; private set; } = true; + public bool HasWarning { get; private set; } = false; + + public bool HasChecks { get; private set; } = false; + public int SetValue(IEnumerable data) { - if(HasHistory) + if (HasHistory) { - if(historyindex >= type.Length) + if (historyindex >= type.Length) { switch (historytype) { @@ -246,10 +279,56 @@ public int SetValue(IEnumerable data) } int ret = type[historyindex].SetValue(data as byte[] ?? data.ToArray()); historyindex++; + IsValid = true; + HasWarning = false; return ret; } else - return Value.SetValue(data as byte[] ?? data.ToArray()); + { + int ret = Value.SetValue(data as byte[] ?? data.ToArray()); + + if(validExpr != null) + { + if (validExpr.Parameters.ContainsKey("value")) + { + validExpr.Parameters["value"] = GetValue(); + } + else + { + validExpr.Parameters.Add("value", GetValue()); + } + try + { + IsValid = (bool)validExpr.Evaluate(); + } + catch(InvalidCastException) + { + throw new XmlException($"Error in Element {(Parent.Parent as DataMessage)?.Name}:{Parent.Name}:{Name} Invalid ValidExpression. Expression must return a boolean"); + } + } + + if (warningExpr != null) + { + if (warningExpr.Parameters.ContainsKey("value")) + { + warningExpr.Parameters["value"] = GetValue(); + } + else + { + warningExpr.Parameters.Add("value", GetValue()); + } + try + { + HasWarning = (bool)warningExpr.Evaluate(); + } + catch(InvalidCastException) + { + throw new XmlException($"Error in Element {(Parent.Parent as DataMessage)?.Name}:{Parent.Name}:{Name} Invalid WarningExpression. Expression must return a boolean"); + } + } + + return ret; + } } public void SetValue(object data) diff --git a/libxcmparse/DataObjects/DataMessage.cs b/libxcmparse/DataObjects/DataMessage.cs index b85cb70..5528257 100644 --- a/libxcmparse/DataObjects/DataMessage.cs +++ b/libxcmparse/DataObjects/DataMessage.cs @@ -10,10 +10,6 @@ namespace libxcmparse.DataObjects public class DataMessage : Message, IEnumerable { public event EventHandler Received; - public static Message MessageFactory(XmlNode messageNode, List knownSymbols) - { - return new DataMessage(messageNode, knownSymbols); - } public static Symbol SymbolFactory(XmlNode symbolNode, bool isNested) { return new DataSymbol(symbolNode, isNested); @@ -23,8 +19,9 @@ public static Entry EntryFactory(XmlNode entryNode) { return new DataEntry(entryNode); } - public DataMessage(XmlNode messageNode, List knownSymbols) : base(messageNode, knownSymbols, SymbolFactory, EntryFactory) + public DataMessage(XmlNode messageNode, InboundConnection inboundConnection, OutboundConnection outboundConnection, string systemName) : base(messageNode, SymbolFactory, EntryFactory, inboundConnection, outboundConnection) { + SystemName = systemName; List sibblings = new List(); foreach (DataSymbol symb in this) { @@ -32,14 +29,27 @@ public DataMessage(XmlNode messageNode, List knownSymbols) : base(messag } foreach (DataSymbol symb in this) { + symb.Parent = this; symb.Sibblings = sibblings; } + + inbound.MessageReceived += Inbound_MessageReceived; + } + + private void Inbound_MessageReceived(object sender, libconnection.MessageReceivedEventArgs e) + { + var msg = e.Message; + if (Match(msg)) + { + Console.WriteLine($"Message {this.Name} received"); + ParseMessage(msg); + } } public void ParseMessage(IEnumerable message) { int offset = 0; - byte[] msgArray = message as byte[] ?? message.ToArray(); + byte[] msgArray = message.Skip(IDByteLength + IDOffset).ToArray(); foreach (var symbol in this) { if(offset >= msgArray.Length) @@ -62,8 +72,33 @@ public void ParseMessage(IEnumerable message) } } Received?.Invoke(this, new EventArgs()); + outbound.TransmitParsedData(this); + } + + public bool CheckValidity() + { + bool ret = true; + foreach(DataSymbol symbol in this) + { + ret &= symbol.CheckValidity(); + } + return ret; } + public bool HasChecks + { + get + { + bool ret = false; + foreach (DataSymbol symbol in this) + { + ret |= symbol.HasChecks; + } + return ret; + } + } + + public byte[] GetData() { if (IsVariableLength) diff --git a/libxcmparse/DataObjects/DataSymbol.cs b/libxcmparse/DataObjects/DataSymbol.cs index dd3c48e..51e4369 100644 --- a/libxcmparse/DataObjects/DataSymbol.cs +++ b/libxcmparse/DataObjects/DataSymbol.cs @@ -61,7 +61,31 @@ public byte[] GetData() return ret; } + public bool CheckValidity() + { + bool ret = true; + foreach(DataEntry entry in this) + { + ret &= entry.IsValid; + } + return ret; + } + + public bool HasChecks + { + get + { + bool ret = false; + foreach (DataEntry entry in this) + { + ret |= entry.HasChecks; + } + return ret; + } + } + public List Sibblings { get; set; } = new List(); + public object Parent { get; set; } = null; public override Symbol Copy(bool fullCopy = false) { diff --git a/libxcmparse/DataTokenFactory.cs b/libxcmparse/DataTokenFactory.cs new file mode 100644 index 0000000..6b10904 --- /dev/null +++ b/libxcmparse/DataTokenFactory.cs @@ -0,0 +1,29 @@ +using libxcm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using libxcmparse.DataObjects; + +namespace libxcmparse +{ + public class DataTokenFactory : ITokenFactory + { + public Command BuildCommand(XmlNode node, InboundConnection inbound, OutboundConnection outbound, string systemName) + { + return new DataCommand(node, inbound, outbound, systemName); + } + + public Message BuildMessage(XmlNode node, InboundConnection inbound, OutboundConnection outbound, string systemName) + { + return new DataMessage(node, inbound, outbound, systemName); + } + + public Symbol BuildSymbol(XmlNode node) + { + return new DataSymbol(node); + } + } +} diff --git a/libxcmparse/ISerializer.cs b/libxcmparse/ISerializer.cs deleted file mode 100644 index c3d2405..0000000 --- a/libxcmparse/ISerializer.cs +++ /dev/null @@ -1,18 +0,0 @@ -using libxcm; -using System; -using System.Collections.Generic; -using System.Text; - -namespace libxcmparse -{ - public interface ISerializer - { - T Serialize(XCMTokenizer tokenizer); - T Serialize(Message message); - T Serialize(Symbol symbol); - T Serialize(Entry entry); - object GetDataObject(Message message); - object GetDataObject(Symbol symbol); - object GetDataObject(Entry entry); - } -} diff --git a/libxcmparse/RecieveDataHandler.cs b/libxcmparse/RecieveDataHandler.cs deleted file mode 100644 index ad533d9..0000000 --- a/libxcmparse/RecieveDataHandler.cs +++ /dev/null @@ -1,37 +0,0 @@ -using libxcmparse.DataObjects; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using xcmparser; - -namespace libxcmparse -{ - public class RecieveDataHandler - { - private List dataMessages = new List(); - - public RecieveDataHandler(XCMParserTokenizer tokenizer) - { - dataMessages.AddRange(tokenizer.GetObjects()); - Tokenizer = tokenizer; - } - - public XCMParserTokenizer Tokenizer { get; } - - public bool ReceiveData(IEnumerable data) - { - bool hasmatched = false; - foreach(var msg in dataMessages) - { - if(msg.Match(data)) - { - msg.ParseMessage(data.Skip(msg.IDByteLength + msg.IDOffset)); - hasmatched = true; - } - } - return hasmatched; - } - } -} diff --git a/libxcmparse/XCMParserTokenizer.cs b/libxcmparse/XCMParserTokenizer.cs deleted file mode 100644 index 2ee1b0a..0000000 --- a/libxcmparse/XCMParserTokenizer.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Xml; -using libxcm; -using libxcmparse.DataObjects; - -namespace xcmparser -{ - public class XCMParserTokenizer : XCMTokenizer - { - public XCMParserTokenizer(XmlDocument doc) : base(doc) - { - } - - public XCMParserTokenizer(XmlElement root, XmlNamespaceManager mngr) : base(root, mngr) - { - } - - public override Symbol BuildSymbol(XmlNode node) - { - return new DataSymbol(node); - } - - public override Command BuildCommand(XmlNode node) - { - return new DataCommand(node, knownSymbols); - } - - public override Message BuildMessage(XmlNode node) - { - return new DataMessage(node, knownSymbols); - } - } -} diff --git a/libxcmparse/libxcmparse.csproj b/libxcmparse/libxcmparse.csproj index d612f37..964ada4 100644 --- a/libxcmparse/libxcmparse.csproj +++ b/libxcmparse/libxcmparse.csproj @@ -1,15 +1,15 @@  - net5.0 + net7.0 - + diff --git a/xcm.xsd b/xcm.xsd index 4df4f82..04bc267 100644 --- a/xcm.xsd +++ b/xcm.xsd @@ -3,11 +3,14 @@ + + - + + @@ -44,6 +47,7 @@ + diff --git a/xcmparser/.gitignore b/xcmparser/.gitignore index 4c26367..dbb5e11 100644 --- a/xcmparser/.gitignore +++ b/xcmparser/.gitignore @@ -1,3 +1,5 @@ +*/Properties/ + ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## @@ -363,4 +365,6 @@ FodyWeavers.xsd *.so -*.o \ No newline at end of file +*.o + +*.csproj.user \ No newline at end of file diff --git a/xcmparser/FMSXCM.xml b/xcmparser/FMSXCM.xml index b9d53b2..2ba33ba 100644 --- a/xcmparser/FMSXCM.xml +++ b/xcmparser/FMSXCM.xml @@ -1,309 +1,87 @@  - - - - - ms - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - m - - - m/s - (height_diff/Header_Timestamp_diff)*1000 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + COM4 + + + 93.177.65.195:1883 + AC1 + false + groundstation + Pick1234 + + + + + + serialConnection + + + + + + primaryOutput + + false + {flightnumber} + + + + + + serialSMP + defaultOut + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xcmparser/KeyValuePairConverter.cs b/xcmparser/KeyValuePairConverter.cs new file mode 100644 index 0000000..85c90ed --- /dev/null +++ b/xcmparser/KeyValuePairConverter.cs @@ -0,0 +1,12 @@ +using CommandLine; +using System; +using System.Collections.Generic; +using System.Linq; + +public class KeyValuePairConverter +{ + public static Dictionary Convert(IEnumerable keyValuePairs) + { + return keyValuePairs.Select(part => part.Split('=')).ToDictionary(split => split[0], split => split[1]); + } +} \ No newline at end of file diff --git a/xcmparser/Program.cs b/xcmparser/Program.cs index 52c37ba..0edb308 100644 --- a/xcmparser/Program.cs +++ b/xcmparser/Program.cs @@ -16,6 +16,7 @@ using libconnection.Interfaces.UDP; using System.Threading.Tasks; using System.Reflection; +using System.Text.RegularExpressions; namespace xcmparser { @@ -23,45 +24,45 @@ class Options { [Option('f', "xcmfile", Required = true, HelpText = "The xcm file with the package definitions")] public string Xcmfile { get; set; } - [Option('p', "pipe", Required = true, HelpText = "The pipe expression on how to receive the data")] - public string Pipe { get; set; } - [Option('o', "outputinterface", HelpText = "Interface definition for the output UDP Server eg: 127.0.0.1:9000", Default = "127.0.0.1:9000")] - public string OutputInterface { get; set; } - - [Option('v', "verbose", HelpText = "Enables console data output")] - public bool Verbose { get; set; } = false; - [Option("noforward", HelpText = "Disables the json output except console output")] - public bool NoForward { get; set; } = false; - [Option("enableinterface", HelpText = "Enables a basic text interface that can be opened by pressing the t key in the console window")] - public bool EnableInterace { get; set; } = false; + [Option] + public IEnumerable Replace { get; set; } } class Program { - static int Main(string[] args) + static async Task Main(string[] args) { - using CancellationTokenSource cts = new CancellationTokenSource(); + using CancellationTokenSource cts = new(); Options opts = null; bool optionsValid = false; - Task receiveTask = null; string assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string workingDir = Directory.GetCurrentDirectory(); int ret = 0; + + Console.CancelKeyPress += (obj, eventargs) => + { + eventargs.Cancel = true; + cts.Cancel(); + }; + try { Parser.Default.ParseArguments(args).WithParsed(o => { optionsValid = true; opts = o; }); if (optionsValid && opts != null) { - XmlReaderSettings settings = new XmlReaderSettings(); + XmlReaderSettings settings = new(); settings.Schemas.Add("http://www.w3schools.com/", Path.Combine(assemblyDir, "xcm.xsd")); settings.ValidationType = ValidationType.Schema; - XmlReader reader = XmlReader.Create(opts.Xcmfile, settings); - XmlDocument doc = new XmlDocument(); + var rawxcm = File.ReadAllText(opts.Xcmfile); + var parameters = KeyValuePairConverter.Convert(opts.Replace); + var replacedxcm = Regex.Replace(rawxcm, @"\{(.+?)\}", m => parameters[m.Groups[1].Value]); + + XmlDocument doc = new(); try { - doc.Load(reader); + doc.LoadXml(replacedxcm); } catch (XmlSchemaValidationException ex) { @@ -69,89 +70,11 @@ static int Main(string[] args) Console.WriteLine(ex.Message); return -1; } - using var client = new UdpTransmitter(null, IPEndPoint.Parse(opts.OutputInterface)); - using var pipe = new StreamPipe(opts.Pipe); - Console.WriteLine("Starting interfaces"); - receiveTask = Task.Run(async () => - { - XCMParserTokenizer tokenizer = new XCMParserTokenizer(doc); - //using TelegrafUDPStream stream = new TelegrafUDPStream(new IPEndPoint(IPAddress.Any, 3550), IPEndPoint.Parse(args[1])); - { - pipe.StartService(); - client.StartService(); - - Console.WriteLine("Upstream interface and downstream interface started"); - var token = cts.Token; - while (!token.IsCancellationRequested) - { - try - { - var msg = await pipe.ReadMessageAsync(token); - lock (opts) - { - ProcessMessage(msg.Data, tokenizer, client, opts); - } - } - catch (OperationCanceledException) - { + var systemfactory = new SystemFactory(new DataTokenFactory()); + var xcmdoc = new XCMDokument(doc, systemfactory); - } - catch (AggregateException ex) - { - if (!(ex.InnerException is TimeoutException)) - { - Console.WriteLine("Unkown exception:"); - Console.WriteLine(ex); - cts.Cancel(); - return false; - } - } - } - return true; - } - }); - XCMParserTokenizer tokenizer = new XCMParserTokenizer(doc); - var token = cts.Token; - bool verbosity = opts.Verbose; - Console.CancelKeyPress += (_, args) => - { - args.Cancel = true; - cts.Cancel(); - Thread.Sleep(1300); - }; - Console.WriteLine("Startup successfull"); - while (!token.IsCancellationRequested) - { - if (Console.KeyAvailable) - { - var key = Console.ReadKey(true).Key; - switch (key) - { - case ConsoleKey.T: - bool enableInterface = false; - lock(opts) - { - enableInterface = opts.EnableInterace; - } - if (enableInterface) - { - lock (opts) - { - opts.Verbose = false; - } - CommandEditStateMachine(tokenizer, pipe); - Console.Clear(); - lock (opts) - { - opts.Verbose = verbosity; - } - } - break; - } - } - Thread.Sleep(10); - } + await xcmdoc.StartConnectionsAsync(cts.Token); } else { @@ -166,7 +89,6 @@ static int Main(string[] args) } cts?.Cancel(); Console.WriteLine("Shutting down"); - receiveTask?.Wait(1000); return ret; } @@ -176,15 +98,15 @@ enum State EditCommand, EditEntry } - - static void CommandEditStateMachine(XCMParserTokenizer tokenizer, DataStream stream) +/* + static void CommandEditStateMachine(XCMParserTokenizer tokenizer, Pipe stream) { State state = State.ShowInfo; bool running = true; var commands = tokenizer.GetObjects(); IEnumerable> enrylist = null; DataCommand selectedCommand = null; - KeyValuePair selectedEntry = new KeyValuePair(null, null); + KeyValuePair selectedEntry = new (null, null); try { while (running) @@ -245,7 +167,7 @@ static void CommandEditStateMachine(XCMParserTokenizer tokenizer, DataStream str //Send the command and return state = State.EditCommand; var data = selectedCommand.GetData(); - stream.PublishDownstreamData(new libconnection.Message(data)); + stream.TransmitMessage(new libconnection.Message(data)); } else { @@ -293,7 +215,7 @@ static void CommandEditStateMachine(XCMParserTokenizer tokenizer, DataStream str } } } - catch(OperationCanceledException) + catch (OperationCanceledException) { } @@ -322,56 +244,42 @@ static void ResetConsole() static IEnumerable> GetCommandEntries(DataCommand msg) { - foreach(DataSymbol symbol in msg) + foreach (DataSymbol symbol in msg.Cast()) { - foreach(DataEntry entry in symbol) + foreach (DataEntry entry in symbol.Cast()) { yield return new KeyValuePair(symbol, entry); } } } - - static bool ProcessMessage(IEnumerable data, XCMParserTokenizer tokenizer, TelegrafUDPStream stream) - { - bool ret = false; - foreach (var msg in tokenizer.GetObjects()) - { - var matcher = msg.GetMatchFunction(); - if (matcher(data)) - { - msg.ParseMessage(data.Skip(msg.IDByteLength + msg.IDOffset)); - ret = true; - Console.WriteLine(TelegrafUDPStream.ConvertDataToJSON(msg)); - stream.SendData(msg); - } - } - return ret; - } - - static bool ProcessMessage(IEnumerable data, XCMParserTokenizer tokenizer, DataStream stream, Options options = null) + static bool ProcessMessage(IEnumerable data, XCMParserTokenizer tokenizer, Pipe stream, out string jsondata, Options options = null) { bool ret = false; + jsondata = string.Empty; foreach (var msg in tokenizer.GetObjects()) { + var processData = data.Skip(msg.IDPrefixLength); var matcher = msg.GetMatchFunction(); - if (matcher(data)) + if (matcher(processData)) { - msg.ParseMessage(data.Skip(msg.IDByteLength + msg.IDOffset)); + msg.ParseMessage(processData.Skip(msg.IDByteLength + msg.IDOffset)); ret = true; - + string name = string.Empty; if (options != null && options.Verbose) { - var json = TelegrafUDPStream.ConvertDataToJSON(msg, true); + var json = JsonConverter.ConvertDataToJSON(msg, ref name, true); Console.WriteLine(json); } if (options == null || !options.NoForward) { - var json = TelegrafUDPStream.ConvertDataToJSON(msg); - stream.PublishUpstreamData(new libconnection.Message(Encoding.UTF8.GetBytes(json))); + var json = JsonConverter.ConvertDataToJSON(msg, ref name); + jsondata = json; + stream.TransmitMessage(new libconnection.Message(Encoding.UTF8.GetBytes(json))); } } } return ret; } +*/ } } diff --git a/xcmparser/SampleJsonCommand.txt b/xcmparser/SampleJsonCommand.txt new file mode 100644 index 0000000..27eafee --- /dev/null +++ b/xcmparser/SampleJsonCommand.txt @@ -0,0 +1,15 @@ +{ + "Type": "sendcommand", + "Name": "Testcommand", + "Fields": [ + { + "Name": "anonymous", + "Elements": [ + { + "Name": "test", + "value": true + } + ] + } +] +} \ No newline at end of file diff --git a/xcmparser/TelegrafUDPStream.cs b/xcmparser/TelegrafUDPStream.cs deleted file mode 100644 index 1107ecf..0000000 --- a/xcmparser/TelegrafUDPStream.cs +++ /dev/null @@ -1,195 +0,0 @@ -using libxcm; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Numerics; -using System.Text; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Threading; -using System.Threading.Tasks; - -namespace xcmparser -{ - public class BigIntegerConverter : JsonConverter - { - public override BigInteger Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType != JsonTokenType.Number) - throw new JsonException(string.Format("Found token {0} but expected token {1}", reader.TokenType, JsonTokenType.Number)); - using var doc = JsonDocument.ParseValue(ref reader); - return BigInteger.Parse(doc.RootElement.GetRawText(), NumberFormatInfo.InvariantInfo); - } - - public override void Write(Utf8JsonWriter writer, BigInteger value, JsonSerializerOptions options) - { - var s = value.ToString(NumberFormatInfo.InvariantInfo); - using var doc = JsonDocument.Parse(s); - doc.WriteTo(writer); - } - } - internal class TelegrafUDPStream : IDisposable - { - - private readonly UdpClient client; - private Task task; - private CancellationTokenSource cts = new CancellationTokenSource(); - private ConcurrentQueue receivedData = new ConcurrentQueue(); - private bool isDisposed = false; - - public event EventHandler ReceivedData; - public TelegrafUDPStream(IPEndPoint Receiveendpoint, IPEndPoint transmitEndpoint) - { - client = new UdpClient(Receiveendpoint); - client.Connect(transmitEndpoint); - task = Task.Factory.StartNew(async () => - { - while (!cts.IsCancellationRequested) - { - try - { - var receiveTask = client.ReceiveAsync(); - var timer = Task.Delay(500); - - var finishedTask = await Task.WhenAny(receiveTask, timer); - if (finishedTask == receiveTask) - { - var result = receiveTask.Result; - receivedData.Enqueue(result.Buffer); - ReceivedData?.Invoke(this, new EventArgs()); - } - } - catch (Exception) - { - - } - } - }, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); - } - - ~TelegrafUDPStream() - { - Dispose(); - } - - public byte[] ReadMessage() - { - byte[] ret; - if(receivedData.TryDequeue(out ret)) - { - return ret; - } - else - { - return new byte[0]; - } - } - - public async Task ReadMessageAsync() - { - TaskCompletionSource tcs = new TaskCompletionSource(); - EventHandler f = (sender, args) => - { - tcs.SetResult(ReadMessage()); - }; - ReceivedData += f; - byte[] ret = await tcs.Task; - ReceivedData -= f; - return ret; - } - - private static object SymbolToTagedObject(Symbol symb) - { - Dictionary tags = new Dictionary(); - foreach(var entry in symb) - { - var val = entry.GetValue(); - string name = entry.Name; - switch (val) - { - case bool: - name += "_bool"; - break; - case string: - name += "_string"; - break; - default: - break; - } - tags.Add(name, val); - } - return tags; - } - - public static byte[] ConvertDataToJSONByte(Message msg) - { - return Encoding.UTF8.GetBytes(ConvertDataToJSON(msg)); - } - public static string ConvertDataToJSON(Message msg, bool pretty = false) - { - Dictionary tags = new Dictionary(); - foreach (var symbol in msg) - { - string name = symbol.Name; - int counter = 0; - if(string.IsNullOrWhiteSpace(name)) - { - do - { - name = "Anonymous" + counter; - counter++; - }while(tags.ContainsKey(name)); - } - tags.Add(name, SymbolToTagedObject(symbol)); - } - JsonSerializerOptions options = new JsonSerializerOptions(); - options.Converters.Add(new BigIntegerConverter()); - options.WriteIndented = pretty; - return JsonSerializer.Serialize(new - { - MessageName = msg.Name, - Fields = tags - },options); - } - - public void SendData(Message msg) - { - byte[] data = ConvertDataToJSONByte(msg); - client.Send(data, data.Length); - } - - public async Task SendDataAsync(Message msg) - { - await Task.Run(() => - { - SendData(msg); - }); - } - - public void Dispose() - { - if(!isDisposed) - { - cts?.Cancel(); - task?.Wait(2000); - try - { - client?.Close(); - } - catch (Exception) - { - - } - isDisposed = true; - } - task?.Dispose(); - cts?.Dispose(); - client?.Dispose(); - } - } -} diff --git a/xcmparser/xcmparser.csproj b/xcmparser/xcmparser.csproj index 12ad4b2..1ab7364 100644 --- a/xcmparser/xcmparser.csproj +++ b/xcmparser/xcmparser.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 @@ -12,7 +12,8 @@ - + + @@ -22,6 +23,12 @@ + + Always + + + Always + Always diff --git a/xcmparser/xcmparser.csproj.user b/xcmparser/xcmparser.csproj.user deleted file mode 100644 index d553b2e..0000000 --- a/xcmparser/xcmparser.csproj.user +++ /dev/null @@ -1,11 +0,0 @@ - - - - <_LastSelectedProfileId>D:\Projekte\xcode\xcmparser\Properties\PublishProfiles\FolderProfile.pubxml - - - - Designer - - - \ No newline at end of file diff --git a/xcodegen.sln b/xcodegen.sln index f007ddc..0b3c2bd 100644 --- a/xcodegen.sln +++ b/xcodegen.sln @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31912.275 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xcodegen", "xcodegen\xcodegen.csproj", "{B2BE3377-883E-484E-B22C-4D7C18A03E78}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "libxcm", "libxcm\libxcm.csproj", "{7E825ACA-B34F-4F11-B160-AC9745DE6B6F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xcmparser", "xcmparser\xcmparser.csproj", "{CCF105B3-FC6E-4BB9-BAE1-85B3320E9640}" @@ -23,14 +21,6 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B2BE3377-883E-484E-B22C-4D7C18A03E78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B2BE3377-883E-484E-B22C-4D7C18A03E78}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B2BE3377-883E-484E-B22C-4D7C18A03E78}.Debug|x64.ActiveCfg = Debug|Any CPU - {B2BE3377-883E-484E-B22C-4D7C18A03E78}.Debug|x64.Build.0 = Debug|Any CPU - {B2BE3377-883E-484E-B22C-4D7C18A03E78}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B2BE3377-883E-484E-B22C-4D7C18A03E78}.Release|Any CPU.Build.0 = Release|Any CPU - {B2BE3377-883E-484E-B22C-4D7C18A03E78}.Release|x64.ActiveCfg = Release|Any CPU - {B2BE3377-883E-484E-B22C-4D7C18A03E78}.Release|x64.Build.0 = Release|Any CPU {7E825ACA-B34F-4F11-B160-AC9745DE6B6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7E825ACA-B34F-4F11-B160-AC9745DE6B6F}.Debug|Any CPU.Build.0 = Debug|Any CPU {7E825ACA-B34F-4F11-B160-AC9745DE6B6F}.Debug|x64.ActiveCfg = Debug|Any CPU diff --git a/xcodegen/.gitignore b/xcodegen/.gitignore index 4c26367..dbb5e11 100644 --- a/xcodegen/.gitignore +++ b/xcodegen/.gitignore @@ -1,3 +1,5 @@ +*/Properties/ + ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## @@ -363,4 +365,6 @@ FodyWeavers.xsd *.so -*.o \ No newline at end of file +*.o + +*.csproj.user \ No newline at end of file diff --git a/xcodegen/FMSXCM.xml b/xcodegen/FMSXCM.xml deleted file mode 100644 index 5e2ed21..0000000 --- a/xcodegen/FMSXCM.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/xcodegen/Program.cs b/xcodegen/Program.cs index d8b3927..b2d171d 100644 --- a/xcodegen/Program.cs +++ b/xcodegen/Program.cs @@ -11,6 +11,7 @@ using System.Xml.Schema; using System.Reflection; using CommandLine; +using System.Threading; namespace xcodegen { @@ -18,12 +19,12 @@ class Options { [Option('f', "xcmfile", Required = true, HelpText = "The xcm file with the package definitions")] public string Xcmfile { get; set; } - [Option('t', "templatefolder", Required = false, HelpText = "The folder that contains the templates")] + [Option('t', "templatefolder", Required = true, HelpText = "The folder that contains the templates")] public string TemplateFolder { get; set; } = string.Empty; - [Option('o', "outputfolder", Required = false, HelpText = "The folder where to write the output files")] + [Option('o', "outputfolder", Required = true, HelpText = "The folder where to write the output files")] public string OutputFolder { get; set; } = string.Empty; [Option('n', "filename", Required = false, HelpText = "The basefilename (without extension) for the generated output files", Default = "xcode")] - public string FileName { get; set; } + public string FileName { get; set; } = "xcode"; [Option("swap", HelpText = "Swap messages and commands in the output")] public bool Swap { get; set; } = false; } @@ -100,69 +101,75 @@ static int Main(string[] args) } TypeGenerator typegenerator = new TypeGenerator(Path.Combine(assemblyDir, "cdtypes.xml")); - XCMTokenizer tokenizer = new XCMTokenizer(doc); - int maxmessagesize = 0; - int maxcommandsize = 0; + using CancellationTokenSource cts = new CancellationTokenSource(); - foreach (var message in tokenizer.GetObjects()) + var tokenizerFactory = new XCMFactory(); + var xcmdoc = new XCMDokument(doc, tokenizerFactory, cts); + + foreach(var tokenizer in xcmdoc.GetTokenizers()) { - if (message.GetMaximumByteLength() > maxmessagesize) + int maxmessagesize = 0; + int maxcommandsize = 0; + foreach (var message in tokenizer.GetObjects()) { - maxmessagesize = message.GetMaximumByteLength(); + if(message.GetMaximumByteLength() > maxmessagesize) + { + maxmessagesize= message.GetMaximumByteLength(); + } } - } - - foreach (var cmd in tokenizer.GetObjects()) - { - if (cmd.GetMaximumByteLength() > maxcommandsize) + foreach(var command in tokenizer.GetObjects()) { - maxcommandsize = cmd.GetMaximumByteLength(); + if(command.GetMaximumByteLength() > maxcommandsize) + { + maxcommandsize= command.GetMaximumByteLength(); + } } - } - - object messages; - object commands; - if(opts.Swap) - { - commands = CreateTemplateObject(tokenizer.GetObjects().ToList(), typegenerator); - messages = CreateTemplateObject(tokenizer.GetObjects().Cast().ToList(), typegenerator); - } - else - { - messages = CreateTemplateObject(tokenizer.GetObjects().ToList(), typegenerator); - commands = CreateTemplateObject(tokenizer.GetObjects().Cast().ToList(), typegenerator); - } + object messages; + object commands; - foreach (string filepath in Directory.GetFiles(templateFolder)) - { - if (Path.GetExtension(filepath) == ".sbntxt") + if (opts.Swap) { - string filename = Path.GetFileName(filepath); - string extension = filename.Substring(filename.IndexOf('.'), filename.LastIndexOf('.') - filename.IndexOf('.')); - string outputFileName = opts.FileName + extension; - string template = filepath; - var tmp = Template.Parse(File.ReadAllText(template), template); - var parsed = tmp.Render(new - { - messages, - commands, - maxmessagesize, - maxcommandsize, - outputfilename = outputFileName, - currentdate = DateTime.Now - }); - string f = Path.Combine(outputFolder, outputFileName); - File.WriteAllText(f, parsed); - Console.WriteLine("Generated file: " + f); + commands = CreateTemplateObject(tokenizer.GetObjects().ToList(), typegenerator); + messages = CreateTemplateObject(tokenizer.GetObjects().Cast().ToList(), typegenerator); } else { - string f = Path.Combine(outputFolder, Path.GetFileName(filepath)); - File.Copy(filepath, f); - Console.WriteLine("Copied file: " + f); + messages = CreateTemplateObject(tokenizer.GetObjects().ToList(), typegenerator); + commands = CreateTemplateObject(tokenizer.GetObjects().Cast().ToList(), typegenerator); } + + foreach (string filepath in Directory.GetFiles(templateFolder)) + { + if (Path.GetExtension(filepath) == ".sbntxt") + { + string filename = Path.GetFileName(filepath); + string extension = filename.Substring(filename.IndexOf('.'), filename.LastIndexOf('.') - filename.IndexOf('.')); + string outputFileName = opts.FileName + "_" + tokenizer.Name + extension; + string template = filepath; + var tmp = Template.Parse(File.ReadAllText(template), template); + var parsed = tmp.Render(new + { + messages, + commands, + maxmessagesize, + maxcommandsize, + outputfilename = outputFileName, + currentdate = DateTime.Now + }); + string f = Path.Combine(outputFolder, outputFileName); + File.WriteAllText(f, parsed); + Console.WriteLine("Generated file: " + f); + } + else + { + string f = Path.Combine(outputFolder, Path.GetFileName(filepath)); + File.Copy(filepath, f); + Console.WriteLine("Copied file: " + f); + } + } + } return 0; } diff --git a/xcodegen/pruefstand.xml b/xcodegen/pruefstand.xml new file mode 100644 index 0000000..aad72c5 --- /dev/null +++ b/xcodegen/pruefstand.xml @@ -0,0 +1,53 @@ + + + + + + + smp + + + + + + + console + + + udp + 10.0.1.131:8094 + 0.0.0.0:7000 + + + + + + + + sharkSerial + telegrafStream + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xcodegen/xcodegen.csproj b/xcodegen/xcodegen.csproj index 76e595a..4c54ba0 100644 --- a/xcodegen/xcodegen.csproj +++ b/xcodegen/xcodegen.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 @@ -25,7 +25,7 @@ Always - + Always diff --git a/xcodegen/xcodegen.csproj.user b/xcodegen/xcodegen.csproj.user deleted file mode 100644 index 7a59c35..0000000 --- a/xcodegen/xcodegen.csproj.user +++ /dev/null @@ -1,11 +0,0 @@ - - - - <_LastSelectedProfileId>D:\Projekte\xcode\xcodegen\Properties\PublishProfiles\FolderProfile.pubxml - - - - Designer - - - \ No newline at end of file