diff --git a/RDMSharp/Metadata/DataTree.cs b/RDMSharp/Metadata/DataTree.cs new file mode 100644 index 0000000..fc7cd47 --- /dev/null +++ b/RDMSharp/Metadata/DataTree.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace RDMSharp.Metadata +{ + public readonly struct DataTree : IEquatable + { + public readonly string Name; + public readonly uint Index; + public readonly object? Value; + public readonly string? Unit; + public readonly bool IsCompound; + public readonly DataTreeValueLabel[]? Labels; + public readonly DataTree[]? Children; + public readonly DataTreeIssue[]? Issues; + + private DataTree(string name, uint index, DataTreeIssue[]? issues = null, bool isCompound = false) + { + Name = name; + Index = index; + Issues = issues; + IsCompound = isCompound; + } + public DataTree(DataTree dataTree, uint index) : this(dataTree.Name, index, dataTree.Issues, dataTree.IsCompound) + { + Value = dataTree.Value; + Unit = dataTree.Unit; + Labels = dataTree.Labels; + Children = dataTree.Children; + } + public DataTree(string name, uint index, object value, DataTreeIssue[]? issues = null, string unit = null, DataTreeValueLabel[] labels = null, bool isCompound = false) : this(name, index, issues, isCompound) + { + if (value is IEnumerable || value is DataTree[] children) + throw new ArgumentException($"Use other Constructor if you use {nameof(Children)}"); + + Value = value; + Unit = unit; + Labels = labels; + } + + public DataTree(string name, uint index, DataTree[] children, DataTreeIssue[]? issues = null, bool isCompound = false) : this(name, index, issues, isCompound) + { + Children = children; + } + + public override string ToString() + { + return $"[{Index}] {Name}: {Value}"; + } + + public override bool Equals(object obj) + { + return obj is DataTree tree && Equals(tree); + } + + public bool Equals(DataTree other) + { + return Name == other.Name && + Index == other.Index && + EqualityComparer.Default.Equals(Value, other.Value) && + compairArrays(this, other); + + bool compairArrays(DataTree _this, DataTree other) + { + if (_this.Children != null) + { + if (!_this.Children.SequenceEqual(other.Children)) + return false; + } + else if (other.Children != null) + return false; + if (_this.Issues != null) + { + if (!_this.Issues.SequenceEqual(other.Issues)) + return false; + } + else if (other.Issues != null) + return false; + + return true; + } + } + + public override int GetHashCode() + { + return HashCode.Combine(Name, Index, Value, Children, Issues); + } + + public static bool operator ==(DataTree left, DataTree right) + { + return left.Equals(right); + } + + public static bool operator !=(DataTree left, DataTree right) + { + return !(left == right); + } + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/DataTreeBranch.cs b/RDMSharp/Metadata/DataTreeBranch.cs new file mode 100644 index 0000000..64b209e --- /dev/null +++ b/RDMSharp/Metadata/DataTreeBranch.cs @@ -0,0 +1,443 @@ +using RDMSharp.Metadata.JSON; +using RDMSharp.Metadata.JSON.OneOfTypes; +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Reflection; +using System.Reflection.Metadata; +using System.Runtime.CompilerServices; +using System.Xml.Linq; + +[assembly: InternalsVisibleTo("RDMSharpTests")] +namespace RDMSharp.Metadata +{ + public readonly struct DataTreeBranch : IEquatable + { + public static readonly DataTreeBranch Empty = new DataTreeBranch(); + public static readonly DataTreeBranch Unset = new DataTreeBranch(true); + + public readonly DataTree[] Children; + public readonly bool IsEmpty; + public readonly bool IsUnset; + + public readonly object ParsedObject; + public DataTreeBranch() + { + IsEmpty = true; + } + private DataTreeBranch(bool isUnset) + { + IsUnset = true; + } + public DataTreeBranch(params DataTree[] children) + { + if (children.Length == 0) + IsEmpty = true; + + Children = children; + if (Children.Count(c => c.Index == 0) > 1) + for (uint i = 0; i < Children.Length; i++) + Children[i] = new DataTree(Children[i], i); + } + private DataTreeBranch(object parsedObject, params DataTree[] children): this(children) + { + ParsedObject = parsedObject; + } + public DataTreeBranch(MetadataJSONObjectDefine define, Command.ECommandDublicte commandType, params DataTree[] children): this(children) + { + if (define == null) + throw new ArgumentNullException(); + + ParsedObject = this.getParsedObject(define, commandType); + } + + private object getParsedObject(MetadataJSONObjectDefine define, Command.ECommandDublicte commandType) + { + ushort pid = define.PID; + var definedDataTreeObjectType = MetadataFactory.GetDefinedDataTreeObjectType(define, commandType); + return getParsedObject(pid, definedDataTreeObjectType, commandType); + } + private object getParsedObject(ushort pid, Type definedDataTreeObjectType, Command.ECommandDublicte commandType) + { + if (IsEmpty || IsUnset) + return null; + try + { + if (definedDataTreeObjectType != null) + { + if (definedDataTreeObjectType.IsEnum) + { + var enumAttribute = definedDataTreeObjectType.GetCustomAttributes().FirstOrDefault(a => (ushort)a.Parameter == pid && a.Command == commandType); + + var eChildren = getChildrenUsingPath(enumAttribute, Children); + if (enumAttribute.IsArray) + { + var array = Array.CreateInstance(definedDataTreeObjectType, eChildren.Length); + var aa = eChildren.Select(eC => Enum.ToObject(definedDataTreeObjectType, eC.Value)).ToArray(); + Array.Copy(aa, array, eChildren.Length); + return array; + } + else + return Enum.ToObject(definedDataTreeObjectType, eChildren.Single().Value); + } + + ConstructorInfo[] constructors = definedDataTreeObjectType.GetConstructors(); + var objectAttribute = definedDataTreeObjectType.GetCustomAttributes().FirstOrDefault(a => (ushort)a.Parameter == pid && a.Command == commandType); + + + var children = getChildrenUsingPath(objectAttribute, Children); + DataTree[] getChildrenUsingPath(DataTreeObjectAttribute objectAttribute, DataTree[] children) + { + if (!string.IsNullOrWhiteSpace(objectAttribute.Path)) + { + string[] path = objectAttribute.Path.Split('/'); + while (path.Length >= 1) + { + children = children.FirstOrDefault(c => string.Equals(c.Name, path[0])).Children; + path = path.Skip(1).ToArray(); + } + } + return children; + } + + + foreach (var constructor in constructors) + { + + if (constructor.GetCustomAttribute() is DataTreeObjectConstructorAttribute cAttribute) + { + if (!children.All(c => c.IsCompound)) + return createObjectFromDataTree(children); + else + { + var array = Array.CreateInstance(definedDataTreeObjectType, children.Length); + foreach (var comp in children) + array.SetValue(createObjectFromDataTree(comp.Children), comp.Index); + return array; + } + + + object createObjectFromDataTree(DataTree[] children) + { + var parameters = new List(); + foreach (var param in constructor.GetParameters()) + if (param.GetCustomAttribute() is DataTreeObjectParameterAttribute pAttribute) + { + var children2 = children; + + string name = pAttribute.Name; + string[] path = name.Split('/'); + while (path.Length > 1) + { + children2 = children2.FirstOrDefault(c => string.Equals(c.Name, path[0])).Children; + path = path.Skip(1).ToArray(); + if (path.Length == 1) + name = path[0]; + } + if (!pAttribute.IsArray && children2.FirstOrDefault(c => string.Equals(c.Name, name)) is DataTree child) + parameters.Add(child.Value); + else if (pAttribute.IsArray && children2.Where(c => string.Equals(c.Name, pAttribute.Name)).OfType() is IEnumerable childenum) + { + Type targetType = children2.First().Value.GetType(); + var array = Array.CreateInstance(targetType, children2.Length); + Array.Copy(children2.Select(c => c.Value).ToArray(), array, children2.Length); + parameters.Add(array); + } + else + throw new ArgumentException($"No matching Value found for '{pAttribute.Name}'"); + } + + var instance = constructor.Invoke(parameters.ToArray()); + return instance; + } + } + } + } + + if (Children.Length == 1) + { + DataTree dataTree = Children[0]; + + if (dataTree.Value != null) + return dataTree.Value; + + if (dataTree.Children.GroupBy(c => c.Name).Count() == 1) + { + var list = dataTree.Children.Select(c => c.Value).ToList(); + Type targetType = list.First().GetType(); + var array = Array.CreateInstance(targetType, list.Count); + Array.Copy(list.ToArray(), array, list.Count); + //for (int i = 0; i < list.Count; i++) + // array.SetValue(Convert.ChangeType(list[i], targetType), i); + + return array; + } + } + } + catch (Exception e) + { + throw e; + } + + throw new NotImplementedException(); + } + + public static DataTreeBranch FromObject(object obj, object key, ParameterBag parameterBag, ERDM_Command command) + { + var result = FromObject(obj, key, command, parameterBag.PID); + if (result.IsUnset) + { + var define = MetadataFactory.GetDefine(parameterBag); + if (define == null) + return result; + Command? cmd = null; + switch (command) + { + case ERDM_Command.GET_COMMAND: + if (define.GetRequest.HasValue) + cmd = define.GetRequest; + break; + case ERDM_Command.GET_COMMAND_RESPONSE: + if (define.GetResponse.HasValue) + cmd = define.GetResponse; + break; + case ERDM_Command.SET_COMMAND: + if (define.SetRequest.HasValue) + cmd = define.SetRequest; + break; + case ERDM_Command.SET_COMMAND_RESPONSE: + if (define.SetResponse.HasValue) + cmd = define.SetResponse; + break; + } + if(!cmd.HasValue) + return result; + List children = new List(); + + switch (cmd.Value.EnumValue) + { + case Command.ECommandDublicte.GetRequest: + cmd = define.GetRequest; + break; + case Command.ECommandDublicte.GetResponse: + cmd = define.GetResponse; + break; + case Command.ECommandDublicte.SetRequest: + cmd = define.SetRequest; + break; + case Command.ECommandDublicte.SetResponse: + cmd = define.SetResponse; + break; + } + if (cmd.Value.SingleField.HasValue) + children.Add(getChildren(cmd.Value.SingleField.Value, obj)); + if (cmd.Value.ListOfFields.Length > 0) + { + if (cmd.Value.ListOfFields.Length > 1) + throw new NotImplementedException(); + + + children.Add(getChildren(cmd.Value.ListOfFields[0], obj)); + + } + DataTree getChildren(OneOfTypes oneOf, object o) + { + var oneofOt = oneOf.ObjectType; + if (oneofOt == null && oneOf.ReferenceType.HasValue) + oneofOt = oneOf.ReferenceType.Value.ReferencedObject; + + if (oneofOt != null) + return new DataTree(oneofOt.Name, 0, o); + + throw new NotImplementedException(); + } + if (children.Count != 0) + return new DataTreeBranch(children: children.ToArray()); + } + return result; + } + + public static DataTreeBranch FromObject(object obj, object key, ERDM_Command command, ERDM_Parameter parameter) + { + if (obj == null) + return DataTreeBranch.Empty; + + Type type = obj.GetType(); + + if (type.IsGenericType && typeof(IDictionary).IsAssignableFrom(type.GetGenericTypeDefinition())) + { + Type[] genericArguments = type.GetGenericArguments(); + Type keyType = genericArguments[0]; + Type valueType = genericArguments[1]; + + var tryGetValueMethod = type.GetMethod("TryGetValue"); + object[] parameters = { key, null }; + + bool found = (bool)tryGetValueMethod.Invoke(obj, parameters); + + if (found) + { + // Der Wert wird im zweiten Parameter (Index 1) gespeichert + object value = parameters[1]; + obj = value; + type = value.GetType(); + } + } + + bool isArray = type.IsArray; + + if (isArray) + type = type.GetElementType(); + + if (type.GetCustomAttributes().FirstOrDefault(a => a.Parameter == parameter && a.Command == Tools.ConvertCommandDublicteToCommand(command) && a.IsArray == isArray) is not DataTreeObjectAttribute dataTreeObjectAttribute) + return DataTreeBranch.Unset; + + List children = new List(); + bool isCompound = false; + if (!type.IsEnum) + { + var properties = type.GetProperties().Where(p => p.GetCustomAttributes().Count() != 0).ToArray(); + isCompound = properties.Length > 1; + + if (isArray) + { + Array array = (Array)obj; + for (uint i = 0; i < array.Length; i++) + children.Add(new DataTree(null, i, convertToDataTree(array.GetValue(i), properties, parameter), isCompound: isCompound)); + } + else + children.AddRange(convertToDataTree(obj, properties, parameter)); + } + else + { + DataTreeEnumAttribute enumAttribute = dataTreeObjectAttribute as DataTreeEnumAttribute; + if (isArray) + { + Array array = (Array)obj; + for (uint i = 0; i < array.Length; i++) + children.Add(new DataTree(enumAttribute.Name, i, getUnderlyingValue(array.GetValue(i)))); + } + else + children.Add(new DataTree(enumAttribute.Name, 0, getUnderlyingValue(obj))); + } + + if (!string.IsNullOrWhiteSpace(dataTreeObjectAttribute.Path)) + { + string[] path = dataTreeObjectAttribute.Path.Split('/'); + DataTree? route = null; + for (int i = path.Length; i != 0; i--) + { + if (route.HasValue) + route = new DataTree(path[i - 1], 0, route); + else + route = new DataTree(path[i - 1], 0, children.ToArray()); + } + + return new DataTreeBranch(obj, route.Value); + } + + return new DataTreeBranch(obj, children.ToArray()); + + static DataTree[] convertToDataTree(object value, PropertyInfo[] properties, ERDM_Parameter parameter) + { + List innetChildren = new List(); + Dictionary> deeperChildren = new Dictionary>(); + foreach (var property in properties) + { + var attributes = property.GetCustomAttributes(); + DataTreeObjectPropertyAttribute attribute = attributes.FirstOrDefault(); + if (attributes.Count() != 1) + attribute = attributes.FirstOrDefault(a => a.Parameter == parameter); + + + if (attribute != null) + { + var val = property.GetValue(value); + if (val is Enum) + val = getUnderlyingValue(val); + if (attribute.Name.Contains("/")) + { + string[] path = attribute.Name.Split('/'); + if (!deeperChildren.TryGetValue(path[0], out List ddc)) + { + ddc = new List(); + deeperChildren.TryAdd(path[0], ddc); + } + ddc.Add(new DataTree(path[1], attribute.Index, val)); + } + else + innetChildren.Add(new DataTree(attribute.Name, attribute.Index, val)); + } + } + foreach (var dC in deeperChildren) + { + var index = FindMissingNumbers(innetChildren.Select(ic => (int)ic.Index)).FirstOrDefault(); + innetChildren.Add(new DataTree(dC.Key, (uint)index, children: dC.Value.OrderBy(c => c.Index).ToArray())); + } + return innetChildren.OrderBy(iC => iC.Index).ToArray(); + + static IEnumerable FindMissingNumbers(IEnumerable numbers) + { + // Liste sortieren + var sortedNumbers = numbers.OrderBy(n => n).ToList(); + + // Bereich (Range) bestimmen + int min = sortedNumbers.First(); + int max = sortedNumbers.Last(); + + // Alle erwarteten Zahlen im Bereich erstellen + var fullRange = Enumerable.Range(min, max - min + 1); + + // Fehlende Zahlen durch Differenz finden + return fullRange.Except(sortedNumbers); + } + } + static object getUnderlyingValue(object enumValue) + { + // Ermitteln des zugrunde liegenden Typs + Type underlyingType = Enum.GetUnderlyingType(enumValue.GetType()); + + // Konvertierung des Enum-Werts in den zugrunde liegenden Typ + return Convert.ChangeType(enumValue, underlyingType); + } + } + + public override bool Equals(object obj) + { + return obj is DataTreeBranch branch && Equals(branch); + } + + public bool Equals(DataTreeBranch other) + { + for (int i = 0; i < Children.Length; i++) + { + DataTree me = Children[i]; + if ((other.Children?.Length ?? 0) <= i) + return false; + DataTree ot = other.Children[i]; + if (!me.Equals(ot)) + return false; + } + return true; + // return EqualityComparer.Default.Equals(Children, other.Children); // is not dooing its job + } + + public override int GetHashCode() + { + return HashCode.Combine(Children); + } + + public static bool operator ==(DataTreeBranch left, DataTreeBranch right) + { + return left.Equals(right); + } + + public static bool operator !=(DataTreeBranch left, DataTreeBranch right) + { + return !(left == right); + } + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/DataTreeIssue.cs b/RDMSharp/Metadata/DataTreeIssue.cs new file mode 100644 index 0000000..b9f3fef --- /dev/null +++ b/RDMSharp/Metadata/DataTreeIssue.cs @@ -0,0 +1,20 @@ +using System; + +namespace RDMSharp.Metadata +{ + public readonly struct DataTreeIssue + { + public readonly string Description; + + public DataTreeIssue(string description) + { + if (string.IsNullOrWhiteSpace(description)) + throw new ArgumentNullException($"{nameof(description)} has to be a vaild String"); + Description = description; + } + public override string ToString() + { + return Description; + } + } +} diff --git a/RDMSharp/Metadata/DataTreeObjectAttribute.cs b/RDMSharp/Metadata/DataTreeObjectAttribute.cs new file mode 100644 index 0000000..405f79d --- /dev/null +++ b/RDMSharp/Metadata/DataTreeObjectAttribute.cs @@ -0,0 +1,44 @@ +using RDMSharp.Metadata.JSON; +using RDMSharp.ParameterWrapper; +using System; + +namespace RDMSharp.Metadata; + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)] +public class DataTreeObjectAttribute : Attribute +{ + public readonly ERDM_Parameter Parameter; + public readonly Command.ECommandDublicte Command; + public readonly EManufacturer Manufacturer = EManufacturer.ESTA; + + public readonly bool IsArray; + public readonly string Path; + + public DataTreeObjectAttribute(ERDM_Parameter parameter, Command.ECommandDublicte command, bool isArray = false, string path=null) + { + Parameter = parameter; + Command = command; + IsArray = isArray; + Path = path; + } + public DataTreeObjectAttribute(EManufacturer manufacturer, ERDM_Parameter parameter, Command.ECommandDublicte command, bool isArray = false, string path = null) + : this(parameter, command, isArray, path) + { + Manufacturer = manufacturer; + } +} +[AttributeUsage(AttributeTargets.Enum, AllowMultiple = true)] +public class DataTreeEnumAttribute : DataTreeObjectAttribute +{ + public readonly string Name; + public DataTreeEnumAttribute(ERDM_Parameter parameter, Command.ECommandDublicte command, string name, bool isArray = false, string path = null) + : base(parameter, command, isArray, path) + { + Name = name; + } + public DataTreeEnumAttribute(EManufacturer manufacturer, ERDM_Parameter parameter, Command.ECommandDublicte command, string name, bool isArray = false, string path = null) + : base(manufacturer, parameter, command, isArray, path) + { + Name = name; + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/DataTreeObjectConstructorAttribute.cs b/RDMSharp/Metadata/DataTreeObjectConstructorAttribute.cs new file mode 100644 index 0000000..55bc0ad --- /dev/null +++ b/RDMSharp/Metadata/DataTreeObjectConstructorAttribute.cs @@ -0,0 +1,11 @@ +using System; + +namespace RDMSharp.Metadata; + +[AttributeUsage(AttributeTargets.Constructor)] +public class DataTreeObjectConstructorAttribute : Attribute +{ + public DataTreeObjectConstructorAttribute() + { + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/DataTreeObjectDependeciePropertyAttribute.cs b/RDMSharp/Metadata/DataTreeObjectDependeciePropertyAttribute.cs new file mode 100644 index 0000000..3aa2c85 --- /dev/null +++ b/RDMSharp/Metadata/DataTreeObjectDependeciePropertyAttribute.cs @@ -0,0 +1,21 @@ +using RDMSharp.Metadata.JSON; +using System; + +namespace RDMSharp.Metadata; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)] +public class DataTreeObjectDependeciePropertyAttribute : Attribute +{ + public readonly string Name; + public readonly ERDM_Parameter Parameter; + public readonly Command.ECommandDublicte Command; + public readonly DataTreeObjectDependeciePropertyBag Bag; + + public DataTreeObjectDependeciePropertyAttribute(string name, ERDM_Parameter parameter, Command.ECommandDublicte command) + { + Name = name; + Parameter = parameter; + Command = command; + Bag = new DataTreeObjectDependeciePropertyBag(name, parameter, command); + } +} diff --git a/RDMSharp/Metadata/DataTreeObjectDependeciePropertyBag.cs b/RDMSharp/Metadata/DataTreeObjectDependeciePropertyBag.cs new file mode 100644 index 0000000..5acd64e --- /dev/null +++ b/RDMSharp/Metadata/DataTreeObjectDependeciePropertyBag.cs @@ -0,0 +1,18 @@ +using RDMSharp.Metadata.JSON; + +namespace RDMSharp.Metadata; + +public readonly struct DataTreeObjectDependeciePropertyBag +{ + public readonly string Name; + public readonly ERDM_Parameter Parameter; + public readonly Command.ECommandDublicte Command; + public readonly object Value; + + internal DataTreeObjectDependeciePropertyBag(string name, ERDM_Parameter parameter, Command.ECommandDublicte command) + { + Name = name; + Parameter = parameter; + Command = command; + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/DataTreeObjectParameterAttribute.cs b/RDMSharp/Metadata/DataTreeObjectParameterAttribute.cs new file mode 100644 index 0000000..ea801e2 --- /dev/null +++ b/RDMSharp/Metadata/DataTreeObjectParameterAttribute.cs @@ -0,0 +1,22 @@ +using System; + +namespace RDMSharp.Metadata; + +[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true)] +public class DataTreeObjectParameterAttribute : Attribute +{ + public readonly string Name; + + public readonly ERDM_Parameter? Parameter; + + public readonly bool IsArray; + + public DataTreeObjectParameterAttribute(string name) + { + Name = name; + } + public DataTreeObjectParameterAttribute(ERDM_Parameter parameter, string name) : this(name) + { + Parameter = parameter; + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/DataTreeObjectPropertyAttribute.cs b/RDMSharp/Metadata/DataTreeObjectPropertyAttribute.cs new file mode 100644 index 0000000..485212a --- /dev/null +++ b/RDMSharp/Metadata/DataTreeObjectPropertyAttribute.cs @@ -0,0 +1,24 @@ +using RDMSharp.Metadata.JSON; +using System; +using System.Threading; + +namespace RDMSharp.Metadata; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)] +public class DataTreeObjectPropertyAttribute : Attribute +{ + public readonly string Name; + public readonly uint Index; + + public readonly ERDM_Parameter? Parameter; + + public DataTreeObjectPropertyAttribute(string name, uint index) + { + Name = name; + Index = index; + } + public DataTreeObjectPropertyAttribute(ERDM_Parameter parameter, string name, uint index) : this(name, index) + { + Parameter = parameter; + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/DataTreeValueLabel.cs b/RDMSharp/Metadata/DataTreeValueLabel.cs new file mode 100644 index 0000000..8c0281f --- /dev/null +++ b/RDMSharp/Metadata/DataTreeValueLabel.cs @@ -0,0 +1,14 @@ +namespace RDMSharp.Metadata +{ + public readonly struct DataTreeValueLabel + { + public readonly object Value; + public readonly string Label; + + public DataTreeValueLabel(object value, string label) + { + Value = value; + Label = label; + } + } +} diff --git a/RDMSharp/Metadata/DefineNotFoundException.cs b/RDMSharp/Metadata/DefineNotFoundException.cs new file mode 100644 index 0000000..602a6e7 --- /dev/null +++ b/RDMSharp/Metadata/DefineNotFoundException.cs @@ -0,0 +1,15 @@ +using System; + +namespace RDMSharp.Metadata +{ + public class DefineNotFoundException : Exception + { + public DefineNotFoundException() + { + } + + public DefineNotFoundException(string message) : base(message) + { + } + } +} diff --git a/RDMSharp/Metadata/JSON/Command.cs b/RDMSharp/Metadata/JSON/Command.cs new file mode 100644 index 0000000..ebe4464 --- /dev/null +++ b/RDMSharp/Metadata/JSON/Command.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Metadata.Ecma335; +using System.Text.Json.Serialization; +using RDMSharp.Metadata.JSON.Converter; +using RDMSharp.RDM; +using OneOf = RDMSharp.Metadata.JSON.OneOfTypes.OneOfTypes; + +namespace RDMSharp.Metadata.JSON +{ + [JsonConverter(typeof(CommandConverter))] + public readonly struct Command + { + [JsonConverter(typeof(CustomEnumConverter))] + public enum ECommandDublicte + { + [JsonPropertyName("get_request")] + GetRequest, + [JsonPropertyName("get_response")] + GetResponse, + [JsonPropertyName("set_request")] + SetRequest, + [JsonPropertyName("set_response")] + SetResponse, + [JsonPropertyName("different_pid")] + DifferentDid + } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public readonly ECommandDublicte? EnumValue { get; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public readonly OneOf? SingleField { get; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public readonly OneOf[]? ListOfFields { get; } + + public bool GetIsEmpty() + { + if (EnumValue != null) + return false; + if (SingleField != null) + return false; + if (ListOfFields != null) + return ListOfFields.Length == 0; + + return true; + } + public Command(ECommandDublicte enumValue) + { + EnumValue = enumValue; + } + public Command(OneOf singleField) + { + SingleField = singleField; + } + public Command(OneOf[] listOfFields) + { + ListOfFields = listOfFields; + } + public PDL GetDataLength() + { + if(GetIsEmpty()) + return new PDL(); + if (SingleField.HasValue) + return SingleField.Value.GetDataLength(); + if (ListOfFields != null) + return new PDL(ListOfFields.Select(f => f.GetDataLength()).ToArray()); + + throw new NotSupportedException(); + } + + public CommonPropertiesForNamed[] GetRequiredProperties() + { + if (SingleField.HasValue) + return new CommonPropertiesForNamed[] { SingleField.Value.ObjectType }; + if (ListOfFields != null) + { + List names = new(); + foreach (var field in ListOfFields) + names.Add(field.ObjectType); + return names.ToArray(); + } + throw new NotImplementedException(); + } + public override string ToString() + { + if (EnumValue.HasValue) + return EnumValue.Value.ToString(); + if (SingleField.HasValue) + return SingleField.Value.ToString(); + if (ListOfFields != null) + return $"[ {string.Join("; ", ListOfFields.Select(f => f.ToString()))} ]"; + return base.ToString(); + } + } +} diff --git a/RDMSharp/Metadata/JSON/CommonPropertiesForNamed.cs b/RDMSharp/Metadata/JSON/CommonPropertiesForNamed.cs new file mode 100644 index 0000000..b305a65 --- /dev/null +++ b/RDMSharp/Metadata/JSON/CommonPropertiesForNamed.cs @@ -0,0 +1,34 @@ +using RDMSharp.RDM; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON +{ + public abstract class CommonPropertiesForNamed + { + [JsonPropertyName("name")] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public abstract string Name { get; } + [JsonPropertyName("displayName")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public abstract string DisplayName { get; } + [JsonPropertyName("notes")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public abstract string? Notes { get; } + [JsonPropertyName("resources")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public abstract string[]? Resources { get; } + + public abstract PDL GetDataLength(); + + public abstract byte[] ParsePayloadToData(DataTree dataTree); + public abstract DataTree ParseDataToPayload(ref byte[] data); + + public override string ToString() + { + if(!string.IsNullOrWhiteSpace(DisplayName)) + return DisplayName; + + return Name; + } + } +} diff --git a/RDMSharp/Metadata/JSON/Converter/CommandConverter.cs b/RDMSharp/Metadata/JSON/Converter/CommandConverter.cs new file mode 100644 index 0000000..89eaeb8 --- /dev/null +++ b/RDMSharp/Metadata/JSON/Converter/CommandConverter.cs @@ -0,0 +1,45 @@ +using System.Text.Json; +using System; +using System.Text.Json.Serialization; +using OneOf = RDMSharp.Metadata.JSON.OneOfTypes.OneOfTypes; + +namespace RDMSharp.Metadata.JSON.Converter +{ + public class CommandConverter : JsonConverter + { + public override Command Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + var enumValue = JsonSerializer.Deserialize(ref reader, options); + return new Command(enumValue); + } + else if (reader.TokenType == JsonTokenType.StartObject) + { + var singleField = JsonSerializer.Deserialize(ref reader, options); + return new Command(singleField); + } + else if (reader.TokenType == JsonTokenType.StartArray) + { + var listOfFields = JsonSerializer.Deserialize(ref reader, options); + if (listOfFields.Length == 0) + return new Command(); + return new Command(listOfFields); + } + + throw new JsonException("Unexpected JSON format for FieldContainer."); + } + + public override void Write(Utf8JsonWriter writer, Command value, JsonSerializerOptions options) + { + if (value.GetIsEmpty()) + JsonSerializer.Serialize(writer, new object[0], options); + else if (value.EnumValue.HasValue) + JsonSerializer.Serialize(writer, value.EnumValue.Value, options); + else if (value.SingleField != null) + JsonSerializer.Serialize(writer, value.SingleField.Value, options); + else if (value.ListOfFields != null) + JsonSerializer.Serialize(writer, value.ListOfFields, options); + } + } +} diff --git a/RDMSharp/Metadata/JSON/Converter/CustomEnumConverter.cs b/RDMSharp/Metadata/JSON/Converter/CustomEnumConverter.cs new file mode 100644 index 0000000..e18aa8c --- /dev/null +++ b/RDMSharp/Metadata/JSON/Converter/CustomEnumConverter.cs @@ -0,0 +1,36 @@ +using System; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.Converter +{ + public class CustomEnumConverter : JsonConverter where T : struct, Enum + { + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + string enumValue = reader.GetString(); + + foreach (var field in typeof(T).GetFields()) + { + if (field.GetCustomAttribute()?.Name == enumValue) + { + return (T)field.GetValue(null); + } + } + + throw new JsonException($"Unknown enum value: {enumValue}"); + } + + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + var field = typeof(T).GetField(value.ToString()); + + var attribute = field.GetCustomAttribute(); + string enumString = attribute.Name; + + writer.WriteStringValue(enumString); + } + } + +} diff --git a/RDMSharp/Metadata/JSON/Converter/OneOfTypesConverter.cs b/RDMSharp/Metadata/JSON/Converter/OneOfTypesConverter.cs new file mode 100644 index 0000000..982c005 --- /dev/null +++ b/RDMSharp/Metadata/JSON/Converter/OneOfTypesConverter.cs @@ -0,0 +1,148 @@ +using RDMSharp.Metadata.JSON.OneOfTypes; +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using OneOf = RDMSharp.Metadata.JSON.OneOfTypes.OneOfTypes; + +namespace RDMSharp.Metadata.JSON.Converter +{ + public class OneOfTypesConverter : JsonConverter + { + public override OneOf Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + JsonElement element = JsonSerializer.Deserialize(ref reader, options); + if (!element.TryGetProperty("type", out JsonElement typeProperty)) + { + if (element.TryGetProperty("$ref", out JsonElement refProperty)) + { + var referenceType = element.Deserialize(options); + return new OneOf(referenceType); + } + throw new JsonException("Unexpected JSON format for FieldContainer."); + } + + string type= typeProperty.GetString(); + switch (type) + { + case "bitField": + var bitFieldType = element.Deserialize(options); + return new OneOf(bitFieldType); + + case "bytes": + var bytesType = element.Deserialize(options); + return new OneOf(bytesType); + + case "boolean": + var booleanType = element.Deserialize(options); + return new OneOf(booleanType); + + case "compound": + var compoundType = element.Deserialize(options); + return new OneOf(compoundType); + + case "int8": + var integerTypeInt8 = element.Deserialize>(options); + return new OneOf(integerTypeInt8); + case "uint8": + var integerTypeUInt8 = element.Deserialize>(options); + return new OneOf(integerTypeUInt8); + + case "int16": + var integerTypeInt16 = element.Deserialize>(options); + return new OneOf(integerTypeInt16); + case "uint16": + var integerTypeUInt16 = element.Deserialize>(options); + return new OneOf(integerTypeUInt16); + + case "int32": + var integerTypeInt32 = element.Deserialize>(options); + return new OneOf(integerTypeInt32); + case "uint32": + var integerTypeUInt32 = element.Deserialize>(options); + return new OneOf(integerTypeUInt32); + + case "int64": + var integerTypeInt64 = element.Deserialize>(options); + return new OneOf(integerTypeInt64); + case "uint64": + var integerTypeUInt64 = element.Deserialize>(options); + return new OneOf(integerTypeUInt64); + +#if NET7_0_OR_GREATER + case "int128": + var integerTypeInt128 = element.Deserialize>(options); + return new OneOf(integerTypeInt128); + case "uint128": + var integerTypeUInt128 = element.Deserialize>(options); + return new OneOf(integerTypeUInt128); +#endif + + case "list": + var listType = element.Deserialize(options); + return new OneOf(listType); + + case "pdEnvelope": + var pdEnvelopeType = element.Deserialize(options); + return new OneOf(pdEnvelopeType); + + case "string": + var stringType = element.Deserialize(options); + return new OneOf(stringType); + } + + throw new JsonException($"Unexpected JSON format Type: {type} for FieldContainer."); + } + + public override void Write(Utf8JsonWriter writer, OneOf value, JsonSerializerOptions options) + { + if (value.BitFieldType != null) + JsonSerializer.Serialize(writer, value.BitFieldType, options); + + else if (value.BooleanType != null) + JsonSerializer.Serialize(writer, value.BooleanType, options); + + else if (value.BytesType != null) + JsonSerializer.Serialize(writer, value.BytesType, options); + + else if (value.ReferenceType != null) + JsonSerializer.Serialize(writer, value.ReferenceType, options); + + else if (value.IntegerType_UInt8 != null) + JsonSerializer.Serialize(writer, value.IntegerType_UInt8, options); + else if (value.IntegerType_Int8 != null) + JsonSerializer.Serialize(writer, value.IntegerType_Int8, options); + + else if (value.IntegerType_UInt16 != null) + JsonSerializer.Serialize(writer, value.IntegerType_UInt16, options); + else if (value.IntegerType_Int16 != null) + JsonSerializer.Serialize(writer, value.IntegerType_Int16, options); + + else if (value.IntegerType_UInt32 != null) + JsonSerializer.Serialize(writer, value.IntegerType_UInt32, options); + else if (value.IntegerType_Int32 != null) + JsonSerializer.Serialize(writer, value.IntegerType_Int32, options); + + else if (value.IntegerType_UInt64 != null) + JsonSerializer.Serialize(writer, value.IntegerType_UInt64, options); + else if (value.IntegerType_Int64 != null) + JsonSerializer.Serialize(writer, value.IntegerType_Int64, options); +#if NET7_0_OR_GREATER + else if (value.IntegerType_UInt128 != null) + JsonSerializer.Serialize(writer, value.IntegerType_UInt128, options); + else if (value.IntegerType_Int128 != null) + JsonSerializer.Serialize(writer, value.IntegerType_Int128, options); +#endif + else if (value.StringType != null) + JsonSerializer.Serialize(writer, value.StringType, options); + + else if (value.ListType != null) + JsonSerializer.Serialize(writer, value.ListType, options); + + else if (value.CompoundType != null) + JsonSerializer.Serialize(writer, value.CompoundType, options); + + else if (value.PD_EnvelopeType != null) + JsonSerializer.Serialize(writer, value.PD_EnvelopeType, options); + } + } +} diff --git a/RDMSharp/Metadata/JSON/Converter/SubdeviceTypeConverter.cs b/RDMSharp/Metadata/JSON/Converter/SubdeviceTypeConverter.cs new file mode 100644 index 0000000..b7b4219 --- /dev/null +++ b/RDMSharp/Metadata/JSON/Converter/SubdeviceTypeConverter.cs @@ -0,0 +1,33 @@ +using System.Text.Json; +using System; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.Converter +{ + public class SubdeviceTypeConverter : JsonConverter + { + public override SubdeviceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Number) + { + var number = JsonSerializer.Deserialize(ref reader, options); + return new SubdeviceType(number); + } + else if (reader.TokenType == JsonTokenType.StartObject) + { + var objectValue = JsonSerializer.Deserialize(ref reader, options); + return new SubdeviceType(objectValue); + } + + throw new JsonException("Unexpected JSON format for FieldContainer."); + } + + public override void Write(Utf8JsonWriter writer, SubdeviceType value, JsonSerializerOptions options) + { + if (value.Value.HasValue) + JsonSerializer.Serialize(writer, value.Value.Value, options); + else if (value.Range.HasValue) + JsonSerializer.Serialize(writer, value.Range.Value, options); + } + } +} diff --git a/RDMSharp/Metadata/JSON/Converter/SubdevicesForRequestsConverter.cs b/RDMSharp/Metadata/JSON/Converter/SubdevicesForRequestsConverter.cs new file mode 100644 index 0000000..306ef97 --- /dev/null +++ b/RDMSharp/Metadata/JSON/Converter/SubdevicesForRequestsConverter.cs @@ -0,0 +1,32 @@ +using System.Text.Json; +using System; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.Converter +{ + public class SubdevicesForRequestsConverter : JsonConverter + { + public override SubdevicesForRequests Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + var enumValue = JsonSerializer.Deserialize(ref reader, options); + return new SubdevicesForRequests(enumValue); + } + var objectValue = JsonSerializer.Deserialize(ref reader, options); + return new SubdevicesForRequests(objectValue); + } + + public override void Write(Utf8JsonWriter writer, SubdevicesForRequests value, JsonSerializerOptions options) + { + if (value.EnumValue.HasValue) + JsonSerializer.Serialize(writer, value.EnumValue.Value, new JsonSerializerOptions(options) + { + Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }); + else if (value.ObjectValue != null) + JsonSerializer.Serialize(writer, value.ObjectValue, options); + } + } +} diff --git a/RDMSharp/Metadata/JSON/Converter/SubdevicesForResponsesConverter.cs b/RDMSharp/Metadata/JSON/Converter/SubdevicesForResponsesConverter.cs new file mode 100644 index 0000000..114bf17 --- /dev/null +++ b/RDMSharp/Metadata/JSON/Converter/SubdevicesForResponsesConverter.cs @@ -0,0 +1,32 @@ +using System.Text.Json; +using System; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.Converter +{ + public class SubdevicesForResponsesConverter : JsonConverter + { + public override SubdevicesForResponses Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + var enumValue = JsonSerializer.Deserialize(ref reader, options); + return new SubdevicesForResponses(enumValue); + } + var objectValue = JsonSerializer.Deserialize(ref reader, options); + return new SubdevicesForResponses(objectValue); + } + + public override void Write(Utf8JsonWriter writer, SubdevicesForResponses value, JsonSerializerOptions options) + { + if (value.EnumValue.HasValue) + JsonSerializer.Serialize(writer, value.EnumValue.Value, new JsonSerializerOptions(options) + { + Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }); + else if (value.ObjectValue != null) + JsonSerializer.Serialize(writer, value.ObjectValue, options); + } + } +} diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/BitFieldType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/BitFieldType.cs new file mode 100644 index 0000000..648c1aa --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/BitFieldType.cs @@ -0,0 +1,146 @@ +using RDMSharp.RDM; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public class BitFieldType : CommonPropertiesForNamed + { + [JsonPropertyName("name")] + [JsonPropertyOrder(1)] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Name { get; } + + [JsonPropertyName("displayName")] + [JsonPropertyOrder(2)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string DisplayName { get; } + + [JsonPropertyName("notes")] + [JsonPropertyOrder(4)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Notes { get; } + + [JsonPropertyName("resources")] + [JsonPropertyOrder(5)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string[] Resources { get; } + + [JsonPropertyName("type")] + [JsonPropertyOrder(3)] + public string Type { get; } + + [JsonPropertyName("size")] + [JsonPropertyOrder(31)] + public ushort Size { get; } + + [JsonPropertyName("valueForUnspecified")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(32)] + public bool? ValueForUnspecified { get; } + + [JsonPropertyName("bits")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(41)] + public BitType[] Bits { get; } + + [JsonConstructor] + public BitFieldType(string name, + string displayName, + string notes, + string[] resources, + string type, + ushort size, + bool? valueForUnspecified, + BitType[] bits) : base() + { + if (!"bitField".Equals(type)) + throw new ArgumentException($"Argument {nameof(type)} has to be \"bitField\""); + if (size % 8 != 0) + throw new ArgumentOutOfRangeException($"Argument {nameof(size)} has to be a multiple of 8"); + + Name = name; + DisplayName = displayName; + Notes = notes; + Resources = resources; + Type = type; + Size = size; + ValueForUnspecified = valueForUnspecified; + Bits = bits; + } + public BitFieldType(string name, ushort size, BitType[] bits, bool valueForUnspecified = false) : this(name, null, null, null, "bitField", size, valueForUnspecified, bits) + { + } + + public override PDL GetDataLength() + { + return new PDL((uint)(Size / 8)); + } + + public override string ToString() + { + return $"{Name} [ {string.Join("; ", Bits.Select(b => b.ToString()))} ]"; + } + public override byte[] ParsePayloadToData(DataTree dataTree) + { + if (!string.Equals(dataTree.Name, this.Name)) + throw new ArithmeticException($"The given Name from {nameof(dataTree.Name)}({dataTree.Name}) not match this Name({this.Name})"); + if (dataTree.Children.Length != this.Bits.Length) + throw new ArithmeticException($"The given {nameof(dataTree.Children)}.{nameof(dataTree.Children.Length)}({dataTree.Children.Length}) not match {nameof(Bits)}.{nameof(Bits.Length)}({Bits.Length})"); + + bool[] data = new bool[Size]; + if (ValueForUnspecified == true) + for (int i = 0; i < Size; i++) + data[i] = true; + + foreach (DataTree bitDataTree in dataTree.Children) + { + BitType bit = Bits.FirstOrDefault(b=>b.Name== bitDataTree.Name); + if (bit == null) + throw new ArithmeticException($"Can't find matching BitType {bitDataTree.Name}"); + if (Bits.Length <= bitDataTree.Index || Bits[bitDataTree.Index] != bit) + throw new ArithmeticException($"The given DataTree {nameof(bitDataTree.Index)}({bitDataTree.Index}) not match BitType {nameof(bit.Index)}({bit.Index})"); + if (bitDataTree.Value is not bool value) + throw new ArithmeticException($"DataTree Value is not bool"); + + data[bit.Index] = value; + } + + return Tools.ValueToData(data); + } + public override DataTree ParseDataToPayload(ref byte[] data) + { + List bitDataTrees = new List(); + List issueList = new List(); + int byteCount = (Size / 8); + if (byteCount > data.Length) + { + issueList.Add(new DataTreeIssue($"Data length not match given Size/8 ({byteCount})")); + byte[] cloneData = new byte[byteCount]; + Array.Copy(data, cloneData, data.Length); + data = cloneData; + } + bool[] bools = Tools.DataToBoolArray(ref data, Size); + for (uint i = 0; i < Bits.Length; i++) + { + BitType bitType = Bits[i]; + bitDataTrees.Add(new DataTree(bitType.Name, i, bools[bitType.Index])); + } + bool valueForUnspecified = ValueForUnspecified == true; + for(int i = 0; i < bools.Length; i++) + { + if (Bits.Any(b => b.Index == i)) + continue; + + bool bit= bools[i]; + if (bit != valueForUnspecified) + issueList.Add(new DataTreeIssue($"The Bit at Index {i} is Unspecified, but the Value is not {valueForUnspecified} as defined for Unspecified Bits")); + } + var children = bitDataTrees.OrderBy(b => b.Index).ToArray(); + var dataTree = new DataTree(this.Name, 0, children: children, issueList.Count != 0 ? issueList.ToArray() : null); + return dataTree; + } + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/BitType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/BitType.cs new file mode 100644 index 0000000..82520bf --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/BitType.cs @@ -0,0 +1,84 @@ +using System; +using System.Text.Json.Serialization; +using RDMSharp.RDM; + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public class BitType : CommonPropertiesForNamed + { + [JsonConstructor] + public BitType(string name, + string displayName, + string notes, + string[] resources, + string type, + ushort index, + bool? reserved, + bool? valueIfReserved) : base() + { + Name = name; + DisplayName = displayName; + Notes = notes; + Resources = resources; + Type = type; + Index = index; + Reserved = reserved; + ValueIfReserved = valueIfReserved; + } + public BitType(string name, ushort index) : this(name, null, null, null, "bit", index, null, null) + { + } + + [JsonPropertyName("name")] + [JsonPropertyOrder(1)] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Name { get; } + [JsonPropertyName("displayName")] + [JsonPropertyOrder(2)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string DisplayName { get; } + [JsonPropertyName("notes")] + [JsonPropertyOrder(4)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Notes { get; } + [JsonPropertyName("resources")] + [JsonPropertyOrder(5)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string[] Resources { get; } + + [JsonPropertyName("type")] + [JsonPropertyOrder(3)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string Type { get; } + [JsonPropertyName("index")] + [JsonPropertyOrder(21)] + public ushort Index { get; } + [JsonPropertyName("reserved")] + [JsonPropertyOrder(31)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? Reserved { get; } + [JsonPropertyName("valueIfReserved")] + [JsonPropertyOrder(32)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? ValueIfReserved { get; } + + public override PDL GetDataLength() + { + throw new NotSupportedException(); + } + + public override byte[] ParsePayloadToData(DataTree dataTree) + { + throw new NotSupportedException(); + } + public override DataTree ParseDataToPayload(ref byte[] data) + { + throw new NotSupportedException(); + } + + public override string ToString() + { + return $"{Index} -> {Name}"; + } + } +} diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/BooleanType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/BooleanType.cs new file mode 100644 index 0000000..b0dc5fd --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/BooleanType.cs @@ -0,0 +1,118 @@ +using RDMSharp.RDM; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public class BooleanType : CommonPropertiesForNamed + { + [JsonPropertyName("name")] + [JsonPropertyOrder(1)] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Name { get; } + [JsonPropertyName("displayName")] + [JsonPropertyOrder(2)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string DisplayName { get; } + [JsonPropertyName("notes")] + [JsonPropertyOrder(4)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Notes { get; } + [JsonPropertyName("resources")] + [JsonPropertyOrder(5)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string[] Resources { get; } + + [JsonPropertyName("type")] + [JsonPropertyOrder(3)] + public string Type { get; } + [JsonPropertyName("labels")] + [JsonPropertyOrder(5)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public LabeledBooleanType[] Labels { get; } + + + [JsonConstructor] + public BooleanType(string name, + string displayName, + string notes, + string[] resources, + string type, + LabeledBooleanType[] labels) : base() + { + if (!"boolean".Equals(type)) + throw new ArgumentException($"Argument {nameof(type)} has to be \"boolean\""); + + if (((labels?.Length) ?? 2) != 2) + throw new ArgumentException($"Argument {nameof(labels)} has to be null oa an array of 2"); + + Name = name; + DisplayName = displayName; + Notes = notes; + Resources = resources; + Type = type; + Labels = labels; + + if (labels != null) + { + if (labels[0].Value == labels[1].Value) + throw new ArgumentException($"Argument {nameof(labels)}, both Values are the same, one has to be false, the other true"); + } + } + public override string ToString() + { + if (Labels == null) + return Name; + + return $"{Name} [ {string.Join("; ", Labels.Select(l => l.ToString()))} ]"; + } + + public override PDL GetDataLength() + { + return new PDL(1); + } + + public override byte[] ParsePayloadToData(DataTree dataTree) + { + if (!string.Equals(dataTree.Name, this.Name)) + throw new ArithmeticException($"The given Name from {nameof(dataTree.Name)}({dataTree.Name}) not match this Name({this.Name})"); + if(dataTree.Value is bool value) + { + switch (value) + { + case false: + return new byte[] { 0x00 }; + case true: + return new byte[] { 0x01 }; + } + } + throw new ArithmeticException($"The given Object from {nameof(dataTree.Value)} can't be parsed"); + } + + public override DataTree ParseDataToPayload(ref byte[] data) + { + List issueList = new List(); + + uint pdl = GetDataLength().Value.Value; + if (data.Length < pdl) + { + issueList.Add(new DataTreeIssue("Given Data not fits PDL")); + byte[] cloneData = new byte[pdl]; + Array.Copy(data, cloneData, data.Length); + data = cloneData; + } + + + DataTreeValueLabel[] labels = null; + if ((Labels?.Length ?? 0) != 0) + labels = Labels.Select(lb => new DataTreeValueLabel(lb.Value, (lb.DisplayName ?? lb.Name))).ToArray(); + + bool value = false; + value = Tools.DataToBool(ref data); + + return new DataTree(this.Name, 0, value, issueList.Count != 0 ? issueList.ToArray() : null, labels: labels); + } + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/BytesType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/BytesType.cs new file mode 100644 index 0000000..8cedeb7 --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/BytesType.cs @@ -0,0 +1,351 @@ +using RDMSharp.RDM; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public class BytesType : CommonPropertiesForNamed + { + [JsonPropertyName("name")] + [JsonPropertyOrder(1)] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Name { get; } + [JsonPropertyName("displayName")] + [JsonPropertyOrder(2)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string DisplayName { get; } + [JsonPropertyName("notes")] + [JsonPropertyOrder(4)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Notes { get; } + [JsonPropertyName("resources")] + [JsonPropertyOrder(5)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string[] Resources { get; } + + [JsonPropertyName("type")] + [JsonPropertyOrder(3)] + public string Type { get; } + [JsonPropertyName("format")] + [JsonPropertyOrder(11)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string Format { get; } + [JsonPropertyName("minLength")] + [JsonPropertyOrder(12)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public uint? MinLength { get; } + [JsonPropertyName("maxLength")] + [JsonPropertyOrder(13)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public uint? MaxLength { get; } + + + [JsonConstructor] + public BytesType(string name, + string displayName, + string notes, + string[] resources, + string type, + string format, + uint? minLength, + uint? maxLength) : base() + { + if (!"bytes".Equals(type)) + throw new ArgumentException($"Argument {nameof(type)} has to be \"bytes\""); + if (minLength.HasValue && maxLength.HasValue) + if (minLength > maxLength) + throw new ArgumentOutOfRangeException($"Argument {nameof(minLength)} has to be <= {nameof(maxLength)}"); + if (minLength.HasValue) + if (minLength > PDL.MAX_LENGTH) + throw new ArgumentOutOfRangeException($"Argument {nameof(minLength)} has to be <= {PDL.MAX_LENGTH}"); + if (maxLength.HasValue) + if (maxLength > PDL.MAX_LENGTH) + throw new ArgumentOutOfRangeException($"Argument {nameof(maxLength)} has to be <= {PDL.MAX_LENGTH}"); + + Name = name; + DisplayName = displayName; + Notes = notes; + Resources = resources; + Type = type; + Format = format; + MinLength = minLength; + MaxLength = maxLength; + } + + public override string ToString() + { + return Name; + } + + public override PDL GetDataLength() + { + uint length = 0; + string format = Format; + bool noFixedSize = false; + if (!string.IsNullOrWhiteSpace(Format) && Format.EndsWith("[]")) + format = Format.Replace("[]", ""); + switch (format) + { + case "mac-address": + case "uid": + length = 6; + break; + case "ipv4": + case "float": + length = 4; + break; + case "ipv6": + case "uuid": + case "guid": + length = 16; + break; + case "double": + length = 8; + break; + case "pid": + length = 2; + break; + default: + noFixedSize = true; + break; + } + if (!string.IsNullOrWhiteSpace(Format) && Format.EndsWith("[]")) + return new PDL(0, (uint)(Math.Truncate((double)PDL.MAX_LENGTH / length) * length)); + else if (!noFixedSize) + return new PDL(length); + + return new PDL((uint)(MinLength ?? 1), (uint)(MaxLength ?? PDL.MAX_LENGTH)); + } + public override byte[] ParsePayloadToData(DataTree dataTree) + { + if (!string.Equals(dataTree.Name, this.Name)) + throw new ArithmeticException($"The given Name from {nameof(dataTree.Name)}({dataTree.Name}) not match this Name({this.Name})"); + + if (!string.IsNullOrWhiteSpace(Format) && Format.EndsWith("[]") && dataTree.Value is Array typedArray) + { + List bytes = new List(); + string format = Format.Replace("[]", ""); + for (int i = 0; i < typedArray.Length; i++) + { + object value = typedArray.GetValue(i); + bytes.AddRange(parseData(format, value)); + if (value is string) + bytes.Add(0); //Null-Delimiter + } + return bytes.ToArray(); + } + else + return parseData(Format, dataTree.Value); + + byte[] parseData(string format, object value) + { + Exception e = null; + try + { + switch (format) + { + //Known from E1.37-5 (2024) + case "uid" when value is UID uid: + return uid.ToBytes().ToArray(); + case "ipv4" when value is IPv4Address ipv4: + return (byte[])ipv4; + case "ipv6" when value is IPv6Address ipv6: + return (byte[])ipv6; + case "mac-address" when value is MACAddress macAddress: + return (byte[])macAddress; + + //Known from E1.37-5 (2024) as uuid + case "uuid" when value is Guid uuid: + return uuid.ToByteArray(); + case "guid" when value is Guid guid: + return guid.ToByteArray(); + + //Additional added, because there is no fancy way to di this with E1.37-5 (2024) + case "pid" when value is ERDM_Parameter pid: + return Tools.ValueToData(pid); + + //Additional added, because there is no fancy way to di this with E1.37-5 (2024) + case "double" when value is double _double: + return BitConverter.GetBytes(_double); + case "float" when value is float _float: + return BitConverter.GetBytes(_float); + + + //Additional added, because there is no fancy way to di this with E1.37-5 (2024) + case "ascii" when value is string ascii: + return Encoding.ASCII.GetBytes(ascii); + case "utf8" when value is string utf8: + return Encoding.UTF8.GetBytes(utf8); + case "utf32" when value is string utf32: + return Encoding.UTF32.GetBytes(utf32); + case "unicode" when value is string unicode: + return Encoding.Unicode.GetBytes(unicode); + case "big_edian_unicode" when value is string big_edian_unicode: + return Encoding.BigEndianUnicode.GetBytes(big_edian_unicode); + case "latin1" when value is string latin1: + return Encoding.Latin1.GetBytes(latin1); + + //Fallback + default: + if (value is string str) + return Encoding.UTF8.GetBytes(str); + if (value is byte[] byteArray) + return byteArray; + throw new NotImplementedException($"There is no implementation for {nameof(Format)}: {Format} and Value: {value}"); + } + } + catch (Exception ex) + { + e = ex; + } + throw new ArithmeticException($"The given Object of {nameof(Format)}: \"{Format}\" can't be parsed from {nameof(value)}: {value}", e); + } + } + public override DataTree ParseDataToPayload(ref byte[] data) + { + List issueList = new List(); + object value = null; + if (!string.IsNullOrWhiteSpace(Format) && Format.EndsWith("[]")) + { + List list = new List(); + while (data.Length > 0) + { + try + { + string format = Format.Replace("[]", ""); + list.Add(parseData(format, ref data)); + } + catch(Exception e) + { + issueList.Add(new DataTreeIssue(e.Message)); + break; + } + } + if (data.Length > 0) + issueList.Add(new DataTreeIssue("Data Length is not 0")); + + if (list.Count == 0) + value = null; + else + { + Type targetType=list.First().GetType(); + var array = Array.CreateInstance(targetType,list.Count); + for (int i = 0; i < list.Count; i++) + array.SetValue(Convert.ChangeType(list[i], targetType), i); + + value = array; + } + } + else + value = parseData(Format, ref data); + + + return new DataTree(this.Name, 0, value, issueList.Count != 0 ? issueList.ToArray() : null); + + object parseData(string format, ref byte[] data) + { + void validateDataLength(int length, ref byte[] data) + { + if (data.Length < length) + throw new ArithmeticException("Data to short"); + } + object value = null; + switch (format) + { + //Known from E1.37-5 (2024) + case "uid": + validateDataLength(6, ref data); + value = new UID(Tools.DataToUShort(ref data), Tools.DataToUInt(ref data)); + break; + case "ipv4": + validateDataLength(4, ref data); + value = new IPv4Address(data.Take(4)); + data = data.Skip(4).ToArray(); + break; + case "ipv6": + validateDataLength(16, ref data); + value = new IPv6Address(data.Take(16)); + data = data.Skip(16).ToArray(); + break; + case "mac-address": + validateDataLength(6, ref data); + value = new MACAddress(data.Take(6)); + data = data.Skip(6).ToArray(); + break; + + //Known from E1.37-5 (2024) as uuid + case "uuid": + case "guid": + validateDataLength(16, ref data); + value = new Guid(data.Take(16).ToArray()); + data = data.Skip(16).ToArray(); + break; + + //Additional added, because there is no fancy way to di this with E1.37-5 (2024) + case "pid": + validateDataLength(2, ref data); + value = Tools.DataToEnum(ref data); + break; + + //Additional added, because there is no fancy way to di this with E1.37-5 (2024) + case "double": + validateDataLength(8, ref data); + value = BitConverter.ToDouble(data.Take(8).ToArray(), 0); + data = data.Skip(8).ToArray(); + break; + case "float": + validateDataLength(4, ref data); + value = BitConverter.ToSingle(data.Take(4).ToArray(), 0); + data = data.Skip(4).ToArray(); + break; + + + //Additional added, because there is no fancy way to di this with E1.37-5 (2024) + case "ascii": + value = getNullDelimitetData(Encoding.ASCII, ref data); + break; + case "utf8": + value = getNullDelimitetData(Encoding.UTF8, ref data); + break; + case "utf32": + value = getNullDelimitetData(Encoding.UTF32, ref data); + break; + case "unicode": + value = getNullDelimitetData(Encoding.Unicode, ref data); + break; + case "big_edian_unicode": + value = getNullDelimitetData(Encoding.BigEndianUnicode, ref data); + break; + case "latin1": + value = getNullDelimitetData(Encoding.Latin1,ref data); + break; + + //Fallback + default: + value = data; + data = data.Skip(data.Length).ToArray(); + issueList.Add(new DataTreeIssue($"No Parser found for {nameof(Format)}: \"{Format}\"")); + break; + } + return value; + + string getNullDelimitetData(Encoding encoding, ref byte[] data) + { + string res = encoding.GetString(data); + if (res.Contains('\0')) + { + res = res.Split('\0')[0]; + int count = encoding.GetByteCount(res + "\0"); + data = data.Skip(count).ToArray(); + } + else + data = new byte[0]; + return res; + } + } + } + } +} diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/CompoundType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/CompoundType.cs new file mode 100644 index 0000000..31e0552 --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/CompoundType.cs @@ -0,0 +1,120 @@ +using RDMSharp.RDM; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text.Json.Serialization; + +[assembly: InternalsVisibleTo("RDMSharpTests")] + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public class CompoundType : CommonPropertiesForNamed + { + [JsonPropertyName("name")] + [JsonPropertyOrder(1)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Name { get; } + [JsonPropertyName("displayName")] + [JsonPropertyOrder(2)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string DisplayName { get; } + [JsonPropertyName("notes")] + [JsonPropertyOrder(4)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Notes { get; } + [JsonPropertyName("resources")] + [JsonPropertyOrder(5)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string[] Resources { get; } + + [JsonPropertyName("type")] + [JsonPropertyOrder(3)] + public string Type { get; } + [JsonPropertyName("subtypes")] + [JsonPropertyOrder(11)] + public OneOfTypes[] Subtypes { get; } + + + [JsonConstructor] + public CompoundType(string name, + string displayName, + string notes, + string[] resources, + string type, + OneOfTypes[] subtypes) + { + if (!"compound".Equals(type)) + throw new ArgumentException($"Argument {nameof(type)} has to be \"compound\""); + + if (((subtypes?.Length) ?? 0) < 1) + throw new ArgumentException($"Argument {nameof(subtypes)} has to be at least a size of 1"); + + Name = name; + DisplayName = displayName; + Notes = notes; + Resources = resources; + Type = type; + Subtypes = subtypes; + } + + public override PDL GetDataLength() + { + return new PDL(Subtypes.Select(s => s.GetDataLength()).ToArray()); + } + public override byte[] ParsePayloadToData(DataTree dataTree) + { + if (!string.Equals(dataTree.Name, this.Name)) + throw new ArithmeticException($"The given Name from {nameof(dataTree.Name)}({dataTree.Name}) not match this Name({this.Name})"); + + if(dataTree.Children.Length!= Subtypes.Length) + throw new ArithmeticException($"The given {nameof(dataTree)} and {nameof(Subtypes)} has different length "); + + List data = new List(); + for (int i = 0; i < dataTree.Children.Length; i++) + { + if (Subtypes[i].IsEmpty()) + throw new ArithmeticException($"The given Object from {nameof(Subtypes)}[{i}] is Empty"); + + data.AddRange(Subtypes[i].ParsePayloadToData(dataTree.Children[i])); + } + + validateDataLength(data.Count); + + return data.ToArray(); + } + public override DataTree ParseDataToPayload(ref byte[] data) + { + List subTypeDataTree = new List(); + List issueList = new List(); + + int dataLength = data.Length; + + for (int i = 0; i < Subtypes.Length; i++) + { + OneOfTypes subType = Subtypes[i]; + subTypeDataTree.Add(new DataTree(subType.ParseDataToPayload(ref data), (uint)i)); + } + dataLength -= data.Length; + + try + { + validateDataLength(dataLength); + } + catch (Exception e) + { + issueList.Add(new DataTreeIssue(e.Message)); + } + + return new DataTree(this.Name, 0, children:subTypeDataTree.OrderBy(b => b.Index).ToArray(), issueList.Count != 0 ? issueList.ToArray() : null, true); + } + + internal bool validateDataLength(int dataLength) + { + if (!GetDataLength().IsValid(dataLength)) + throw new ArithmeticException($"Parsed DataLength not fits Calculated DataLength"); + + return true; + } + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/EIntegerType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/EIntegerType.cs new file mode 100644 index 0000000..add763d --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/EIntegerType.cs @@ -0,0 +1,30 @@ +using RDMSharp.Metadata.JSON.Converter; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + [JsonConverter(typeof(CustomEnumConverter))] + public enum EIntegerType + { + [JsonPropertyName("int8")] + Int8, + [JsonPropertyName("int16")] + Int16, + [JsonPropertyName("int32")] + Int32, + [JsonPropertyName("int64")] + Int64, + [JsonPropertyName("int128")] + Int128, + [JsonPropertyName("uint8")] + UInt8, + [JsonPropertyName("uint16")] + UInt16, + [JsonPropertyName("uint32")] + UInt32, + [JsonPropertyName("uint64")] + UInt64, + [JsonPropertyName("uint128")] + UInt128 + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/IIntegerType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/IIntegerType.cs new file mode 100644 index 0000000..36d67ae --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/IIntegerType.cs @@ -0,0 +1,21 @@ +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public interface IIntegerType + { + string Name { get; } + string DisplayName { get; } + bool? RestrictToLabeled { get; } + string Notes { get; } + EIntegerType Type { get; } + ERDM_SensorUnit? Units { get; } + int? PrefixPower { get; } + int? PrefixBase { get; } + double PrefixMultiplyer { get; } + + bool IsInRange(object number); + object GetMaximum(); + object GetMinimum(); + object Increment(object number); + object IncrementJumpRange(object number); + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/IntegerType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/IntegerType.cs new file mode 100644 index 0000000..dc12f66 --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/IntegerType.cs @@ -0,0 +1,453 @@ +using RDMSharp.RDM; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public class IntegerType : CommonPropertiesForNamed, IIntegerType + { + [JsonPropertyName("name")] + [JsonPropertyOrder(1)] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Name { get; } + [JsonPropertyName("displayName")] + [JsonPropertyOrder(2)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string DisplayName { get; } + [JsonPropertyName("notes")] + [JsonPropertyOrder(4)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Notes { get; } + [JsonPropertyName("resources")] + [JsonPropertyOrder(5)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string[] Resources { get; } + + [JsonPropertyName("type")] + [JsonPropertyOrder(3)] + public EIntegerType Type { get; } + [JsonPropertyName("labels")] + [JsonPropertyOrder(31)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public LabeledIntegerType[] Labels { get; } + [JsonPropertyName("restrictToLabeled")] + [JsonPropertyOrder(32)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? RestrictToLabeled { get; } + [JsonPropertyName("ranges")] + [JsonPropertyOrder(11)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Range[] Ranges { get; } + [JsonPropertyName("units")] + [JsonPropertyOrder(21)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ERDM_SensorUnit? Units { get; } + [JsonPropertyName("prefixPower")] + [JsonPropertyOrder(22)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? PrefixPower { get; } = 0; + [JsonPropertyName("prefixBase")] + [JsonPropertyOrder(23)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? PrefixBase { get; } = 10; + + [JsonIgnore(Condition = JsonIgnoreCondition.Always)] + public double PrefixMultiplyer { get; } + + [JsonConstructor] + public IntegerType(string name, + string displayName, + string notes, + string[] resources, + EIntegerType type, + LabeledIntegerType[] labels, + bool? restrictToLabeled, + Range[] ranges, + ERDM_SensorUnit? units, + int? prefixPower, + int? prefixBase) : base() + { + validateType(type); + Name = name; + DisplayName = displayName; + Notes = notes; + Resources = resources; + Type = type; + Labels = labels; + RestrictToLabeled = restrictToLabeled; + Ranges = ranges; + Units = units; + PrefixPower = prefixPower; + PrefixBase = prefixBase; + + PrefixMultiplyer = Math.Pow(PrefixBase ?? 10, PrefixPower ?? 0); + } + + private static void validateType(EIntegerType type, T dummy = default) + { + switch (dummy) + { + case sbyte when type is not EIntegerType.Int8: + throw new ArgumentException($"Argument {nameof(type)} has to be \"{EIntegerType.Int8}\""); + + case byte when type is not EIntegerType.UInt8: + throw new ArgumentException($"Argument {nameof(type)} has to be \"{EIntegerType.UInt8}\""); + + case short when type is not EIntegerType.Int16: + throw new ArgumentException($"Argument {nameof(type)} has to be \"{EIntegerType.Int16}\""); + + case ushort when type is not EIntegerType.UInt16: + throw new ArgumentException($"Argument {nameof(type)} has to be \"{EIntegerType.UInt16}\""); + + case int when type is not EIntegerType.Int32: + throw new ArgumentException($"Argument {nameof(type)} has to be \"{EIntegerType.Int32}\""); + + case uint when type is not EIntegerType.UInt32: + throw new ArgumentException($"Argument {nameof(type)} has to be \"{EIntegerType.UInt32}\""); + + case long when type is not EIntegerType.Int64: + throw new ArgumentException($"Argument {nameof(type)} has to be \"{EIntegerType.Int64}\""); + + case ulong when type is not EIntegerType.UInt64: + throw new ArgumentException($"Argument {nameof(type)} has to be \"{EIntegerType.UInt64}\""); +#if NET7_0_OR_GREATER + case Int128 when type is not EIntegerType.Int128: + throw new ArgumentException($"Argument {nameof(type)} has to be \"{EIntegerType.Int128}\""); + + case UInt128 when type is not EIntegerType.UInt128: + throw new ArgumentException($"Argument {nameof(type)} has to be \"{EIntegerType.UInt128}\""); +#endif + } + } + + public override string ToString() + { + if (Labels != null) + return $"{Name} {Type} -> [ {string.Join("; ", Labels.Select(l => l.ToString()))} ]"; + + return $"{Name} {Type}"; + } + + public override PDL GetDataLength() + { + switch (Type) + { + case EIntegerType.Int8: + case EIntegerType.UInt8: + return new PDL(1); + + case EIntegerType.Int16: + case EIntegerType.UInt16: + return new PDL(2); + + case EIntegerType.Int32: + case EIntegerType.UInt32: + return new PDL(4); + + case EIntegerType.Int64: + case EIntegerType.UInt64: + return new PDL(8); + } + return new PDL(16); + } + + private T convertFormatedValueToRaw(object formated) + { + if (PrefixMultiplyer == 1) + return (T)formated; + + object rawValue = null; + switch (formated) + { + case double _double: + rawValue = _double / PrefixMultiplyer; + break; + case long _long: + rawValue = _long / PrefixMultiplyer; + break; + case ulong _ulong: + rawValue = _ulong / PrefixMultiplyer; + break; + + default: + return (T)formated; + } + + if (rawValue is not null) + return (T)Convert.ChangeType(rawValue, typeof(T)); + + throw new NotImplementedException(); + } + + private object convertRawValueToFormated(T raw) + { + if (PrefixMultiplyer == 1) + return raw; + + bool isNegativ = Math.Sign(PrefixMultiplyer) == -1; + bool isDezimal = PrefixPower < 0; + + switch (raw) + { + case sbyte int8: + if (isDezimal) + return (double)(PrefixMultiplyer * int8); + if (isNegativ) + return (long)(PrefixMultiplyer * int8); + return (ulong)(PrefixMultiplyer * int8); + + case byte uint8: + if (isDezimal) + return (double)(PrefixMultiplyer * uint8); + if (isNegativ) + return (long)(PrefixMultiplyer * uint8); + return (ulong)(PrefixMultiplyer * uint8); + + case short int16: + if (isDezimal) + return (double)(PrefixMultiplyer * int16); + if (isNegativ) + return (long)(PrefixMultiplyer * int16); + return (ulong)(PrefixMultiplyer * int16); + + case ushort uint16: + if (isDezimal) + return (double)(PrefixMultiplyer * uint16); + if (isNegativ) + return (long)(PrefixMultiplyer * uint16); + return (ulong)(PrefixMultiplyer * uint16); + + case int int32: + if (isDezimal) + return (double)(PrefixMultiplyer * int32); + if (isNegativ) + return (long)(PrefixMultiplyer * int32); + return (ulong)(PrefixMultiplyer * int32); + + case uint uint32: + if (isDezimal) + return (double)(PrefixMultiplyer * uint32); + if (isNegativ) + return (long)(PrefixMultiplyer * uint32); + return (ulong)(PrefixMultiplyer * uint32); + + case long int64: + if (isDezimal) + return (double)(PrefixMultiplyer * int64); + if (isNegativ) + return (long)(PrefixMultiplyer * int64); + return (ulong)(PrefixMultiplyer * int64); + + case ulong uint64: + if (isDezimal) + return (double)(PrefixMultiplyer * uint64); + if (isNegativ) + return (long)(PrefixMultiplyer * uint64); + return (ulong)(PrefixMultiplyer * uint64); + + default: + return raw; + } + throw new NotImplementedException(); + } + + public override byte[] ParsePayloadToData(DataTree dataTree) + { + if (!string.Equals(dataTree.Name, this.Name)) + throw new ArithmeticException($"The given Name from {nameof(dataTree.Name)}({dataTree.Name}) not match this Name({this.Name})"); + + var rawValue = convertFormatedValueToRaw(dataTree.Value); + if (Ranges != null) + { + if (!Ranges.Any(r => r.IsInRange(rawValue))) + throw new ArithmeticException("The Value is not in range of any Range"); + } + var data = Tools.ValueToData(rawValue); + + return data; + } + public override DataTree ParseDataToPayload(ref byte[] data) + { + List issueList = new List(); + uint pdl = GetDataLength().Value.Value; + + if (data.Length < pdl) + { + issueList.Add(new DataTreeIssue("Given Data not fits PDL")); + byte[] cloneData = new byte[pdl]; + Array.Copy(data, cloneData, data.Length); + data = cloneData; + } + + object value = null; + + switch (this.Type) + { + case EIntegerType.Int8: + value = Tools.DataToSByte(ref data); + break; + case EIntegerType.UInt8: + value = Tools.DataToByte(ref data); + break; + case EIntegerType.Int16: + value = Tools.DataToShort(ref data); + break; + case EIntegerType.UInt16: + value = Tools.DataToUShort(ref data); + break; + case EIntegerType.Int32: + value = Tools.DataToInt(ref data); + break; + case EIntegerType.UInt32: + value = Tools.DataToUInt(ref data); + break; + case EIntegerType.Int64: + value = Tools.DataToLong(ref data); + break; + case EIntegerType.UInt64: + value = Tools.DataToULong(ref data); + break; +#if NET7_0_OR_GREATER + case EIntegerType.Int128: + value = Tools.DataToInt128(ref data); + break; + case EIntegerType.UInt128: + value = Tools.DataToUInt128(ref data); + break; +#endif + } + if (Ranges != null) + { + if (!Ranges.Any(r => r.IsInRange((T)value))) + issueList.Add(new DataTreeIssue("The Value is not in range of any Range")); + } + + string unit = null; + if (Units.HasValue) + unit = Tools.GetUnitSymbol(Units.Value); + DataTreeValueLabel[] labels = null; + if ((Labels?.Length ?? 0) != 0) + labels = Labels.Select(lb => new DataTreeValueLabel(lb.Value, (lb.DisplayName ?? lb.Name))).ToArray(); + + return new DataTree(this.Name, 0, convertRawValueToFormated((T)value), issueList.Count != 0 ? issueList.ToArray() : null, unit, labels); + } + + public bool IsInRange(object number) + { + if (Ranges != null) + return Ranges.Any(r => r.IsInRange((T)number)); + + return new Range((T)GetMinimum(), (T)GetMaximum()).IsInRange((T)number); + } + + public object GetMaximum() + { + if (Ranges != null) + return Ranges.Max(r => r.Maximum); + + switch (this.Type) + { + case EIntegerType.Int8: + return sbyte.MaxValue; + case EIntegerType.UInt8: + return byte.MaxValue; + case EIntegerType.Int16: + return short.MaxValue; + case EIntegerType.UInt16: + return ushort.MaxValue; + case EIntegerType.Int32: + return int.MaxValue; + case EIntegerType.UInt32: + return uint.MaxValue; + case EIntegerType.Int64: + return long.MaxValue; + case EIntegerType.UInt64: + return ulong.MaxValue; +#if NET7_0_OR_GREATER + case EIntegerType.Int128: + return Int128.MaxValue; + case EIntegerType.UInt128: + return UInt128.MaxValue; +#endif + } + throw new NotImplementedException(); + } + + public object GetMinimum() + { + if (Ranges != null) + return Ranges.Min(r => r.Minimum); + + switch (this.Type) + { + case EIntegerType.Int8: + return sbyte.MinValue; + case EIntegerType.UInt8: + return byte.MinValue; + case EIntegerType.Int16: + return short.MinValue; + case EIntegerType.UInt16: + return ushort.MinValue; + case EIntegerType.Int32: + return int.MinValue; + case EIntegerType.UInt32: + return uint.MinValue; + case EIntegerType.Int64: + return long.MinValue; + case EIntegerType.UInt64: + return ulong.MinValue; +#if NET7_0_OR_GREATER + case EIntegerType.Int128: + return Int128.MinValue; + case EIntegerType.UInt128: + return UInt128.MinValue; +#endif + } + throw new NotImplementedException(); + } + + public object Increment(object number) + { + switch (this.Type) + { + case EIntegerType.Int8: + return (sbyte)((sbyte)number + 1); + case EIntegerType.UInt8: + return (byte)((byte)number + 1); + case EIntegerType.Int16: + return (short)((short)number + 1); + case EIntegerType.UInt16: + return (ushort)((ushort)number + 1); + case EIntegerType.Int32: + return (int)((int)number + 1); + case EIntegerType.UInt32: + return (uint)((uint)number + 1); + case EIntegerType.Int64: + return (long)((long)number + 1); + case EIntegerType.UInt64: + return (ulong)((ulong)number + 1); +#if NET7_0_OR_GREATER + case EIntegerType.Int128: + return (Int128)((Int128)number + 1); + case EIntegerType.UInt128: + return (UInt128)((UInt128)number + 1); +#endif + } + return number; + } + + public object IncrementJumpRange(object number) + { + object incremented = Increment(number); + if (IsInRange(incremented)) + return incremented; + + if (Ranges != null) + return Ranges.Where(r => r.IsBelow((T)incremented)).Min(r => r.Minimum); + + return false; + } + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/LabeledBooleanType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/LabeledBooleanType.cs new file mode 100644 index 0000000..8ded8c2 --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/LabeledBooleanType.cs @@ -0,0 +1,66 @@ +using System; +using System.Text.Json.Serialization; +using RDMSharp.RDM; + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public class LabeledBooleanType : CommonPropertiesForNamed + { + [JsonPropertyName("name")] + [JsonPropertyOrder(1)] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Name { get; } + [JsonPropertyName("displayName")] + [JsonPropertyOrder(2)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string DisplayName { get; } + [JsonPropertyName("notes")] + [JsonPropertyOrder(4)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Notes { get; } + [JsonPropertyName("resources")] + [JsonPropertyOrder(5)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string[] Resources { get; } + + [JsonPropertyName("value")] + [JsonPropertyOrder(3)] + public bool Value { get; } + + [JsonConstructor] + public LabeledBooleanType(string name, + string displayName, + string notes, + string[] resources, + bool value) : base() + { + Name = name; + DisplayName = displayName; + Notes = notes; + Resources = resources; + Value = value; + } + public LabeledBooleanType(string name, bool value) : this(name, null, null, null, value) + { + } + + public override string ToString() + { + return $"{Value} -> {Name}"; + } + + public override PDL GetDataLength() + { + throw new NotSupportedException(); + } + + public override byte[] ParsePayloadToData(DataTree dataTree) + { + throw new NotSupportedException(); + } + public override DataTree ParseDataToPayload(ref byte[] data) + { + throw new NotSupportedException(); + } + } +} diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/LabeledIntegerType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/LabeledIntegerType.cs new file mode 100644 index 0000000..5f88836 --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/LabeledIntegerType.cs @@ -0,0 +1,67 @@ +using RDMSharp.RDM; +using System; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public class LabeledIntegerType : CommonPropertiesForNamed + { + [JsonPropertyName("name")] + [JsonPropertyOrder(1)] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Name { get; } + [JsonPropertyName("displayName")] + [JsonPropertyOrder(2)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string DisplayName { get; } + [JsonPropertyName("notes")] + [JsonPropertyOrder(4)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Notes { get; } + [JsonPropertyName("resources")] + [JsonPropertyOrder(5)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string[] Resources { get; } + + [JsonPropertyName("value")] + [JsonPropertyOrder(3)] + public long Value { get; } + + [JsonConstructor] + public LabeledIntegerType(string name, + string displayName, + string notes, + string[] resources, + long value) : base() + { + Name = name; + DisplayName = displayName; + Notes = notes; + Resources = resources; + Value = value; + } + + public LabeledIntegerType(string name, long value): this(name, null, null, null, value) + { + + } + + public override string ToString() + { + return $"{Value} -> {Name}"; + } + public override PDL GetDataLength() + { + throw new NotSupportedException(); + } + + public override byte[] ParsePayloadToData(DataTree dataTree) + { + throw new NotSupportedException(); + } + public override DataTree ParseDataToPayload(ref byte[] data) + { + throw new NotSupportedException(); + } + } +} diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/ListType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/ListType.cs new file mode 100644 index 0000000..7c30ba2 --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/ListType.cs @@ -0,0 +1,177 @@ +using RDMSharp.RDM; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text.Json.Serialization; + +[assembly: InternalsVisibleTo("RDMSharpTests")] + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public class ListType : CommonPropertiesForNamed + { + [JsonPropertyName("name")] + [JsonPropertyOrder(1)] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Name { get; } + [JsonPropertyName("displayName")] + [JsonPropertyOrder(2)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string DisplayName { get; } + [JsonPropertyName("notes")] + [JsonPropertyOrder(4)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Notes { get; } + [JsonPropertyName("resources")] + [JsonPropertyOrder(5)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string[] Resources { get; } + + [JsonPropertyName("type")] + [JsonPropertyOrder(3)] + public string Type { get; } + [JsonPropertyName("itemType")] + [JsonPropertyOrder(21)] + public OneOfTypes ItemType { get; } + [JsonPropertyName("minItems")] + [JsonPropertyOrder(31)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public uint? MinItems { get; } + [JsonPropertyName("maxItems")] + [JsonPropertyOrder(32)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public uint? MaxItems { get; } + + + [JsonConstructor] + public ListType(string name, + string displayName, + string notes, + string[] resources, + string type, + OneOfTypes itemType, + uint? minItems, + uint? maxItems) : base() + { + if (!"list".Equals(type)) + throw new ArgumentException($"Argument {nameof(type)} has to be \"list\""); + + if (itemType.IsEmpty()) + throw new ArgumentException($"Argument {nameof(itemType)} is Empty, this is not allowed"); + + Name = name; + DisplayName = displayName; + Notes = notes; + Resources = resources; + Type = type; + ItemType = itemType; + MinItems = minItems; + MaxItems = maxItems; + } + + public override string ToString() + { + return DisplayName ?? Name; + } + + public override PDL GetDataLength() + { + uint min = 0; + uint max = 0; + + if (MinItems.HasValue) + min = MinItems.Value; + if (MaxItems.HasValue) + max = MaxItems.Value; + + PDL itemPDL = ItemType.GetDataLength(); + if (itemPDL.Value.HasValue) + { + min *= itemPDL.Value.Value; + max *= itemPDL.Value.Value; + } + else + { + if (itemPDL.MinLength.HasValue) + min *= itemPDL.MinLength.Value; + if (itemPDL.MaxLength.HasValue) + max *= itemPDL.MaxLength.Value; + } + + if (max == 0) + if (!MaxItems.HasValue) + max = PDL.MAX_LENGTH; + + if (min == max) + return new PDL(min); + + return new PDL(min, max); + } + public override byte[] ParsePayloadToData(DataTree dataTree) + { + if (!string.Equals(dataTree.Name, this.Name)) + throw new ArithmeticException($"The given Name from {nameof(dataTree.Name)}({dataTree.Name}) not match this Name({this.Name})"); + + List data = new List(); + for (int i = 0; i < dataTree.Children.Length; i++) + data.AddRange(ItemType.ParsePayloadToData(dataTree.Children[i])); + + validateDataLength(data.Count); + + return data.ToArray(); + } + + public override DataTree ParseDataToPayload(ref byte[] data) + { + List dataTrees = new List(); + List issueList = new List(); + + uint index = 0; + int dataLength = data.Length; + while (_continue(ref data)) + { + dataTrees.Add(new DataTree(ItemType.ParseDataToPayload(ref data), index)); + index++; + } + dataLength -= data.Length; + + try + { + validateDataLength(dataLength); + } + catch (Exception e) + { + issueList.Add(new DataTreeIssue(e.Message)); + } + + return new DataTree(Name, 0, children: dataTrees.ToArray(), issueList.Count != 0 ? issueList.ToArray() : null); + + bool _continue(ref byte[] data) + { + if (MaxItems.HasValue) + if (dataTrees.Count > MaxItems.Value) + { + if (dataTrees.Count > 0) + issueList.Add(new DataTreeIssue($"Given data exceeds {nameof(MaxItems)}")); + return false; + } + if (data.Length == 0) + { + if (MinItems.HasValue) + if (dataTrees.Count < MinItems.Value) + issueList.Add(new DataTreeIssue($"Given data falls shorts of {nameof(MinItems)}")); + return false; + } + + return true; + } + } + internal bool validateDataLength(int dataLength) + { + if (!GetDataLength().IsValid(dataLength)) + throw new ArithmeticException($"Parsed DataLength not fits Calculated DataLength"); + + return true; + } + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/OneOfTypes.cs b/RDMSharp/Metadata/JSON/OneOfTypes/OneOfTypes.cs new file mode 100644 index 0000000..270c068 --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/OneOfTypes.cs @@ -0,0 +1,151 @@ +using RDMSharp.Metadata.JSON.Converter; +using RDMSharp.RDM; +using System; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + [JsonConverter(typeof(OneOfTypesConverter))] + public readonly struct OneOfTypes + { + public readonly CommonPropertiesForNamed ObjectType; + public readonly BitFieldType BitFieldType { get; } + public readonly BytesType BytesType { get; } + public readonly BooleanType BooleanType { get; } + public readonly IntegerType IntegerType_UInt8 { get; } + public readonly IntegerType IntegerType_Int8 { get; } + public readonly IntegerType IntegerType_UInt16 { get; } + public readonly IntegerType IntegerType_Int16 { get; } + public readonly IntegerType IntegerType_UInt32 { get; } + public readonly IntegerType IntegerType_Int32 { get; } + public readonly IntegerType IntegerType_UInt64 { get; } + public readonly IntegerType IntegerType_Int64 { get; } +#if NET7_0_OR_GREATER + public readonly IntegerType IntegerType_UInt128 { get; } + public readonly IntegerType IntegerType_Int128 { get; } +#endif + public readonly ReferenceType? ReferenceType { get; } + public readonly ListType ListType { get; } + public readonly CompoundType CompoundType { get; } + public readonly StringType StringType { get; } + public readonly PD_EnvelopeType PD_EnvelopeType { get; } + + public OneOfTypes(BitFieldType bitFieldType) + { + BitFieldType = bitFieldType; + ObjectType = bitFieldType; + } + public OneOfTypes(BytesType bytesType) + { + BytesType = bytesType; + ObjectType = bytesType; + } + public OneOfTypes(BooleanType booleanType) + { + BooleanType = booleanType; + ObjectType = booleanType; + } + public OneOfTypes(IntegerType integerType_UInt8) + { + IntegerType_UInt8 = integerType_UInt8; + ObjectType = integerType_UInt8; + } + public OneOfTypes(IntegerType integerType_Int8) + { + IntegerType_Int8 = integerType_Int8; + ObjectType = integerType_Int8; + } + public OneOfTypes(IntegerType integerType_UInt16) + { + IntegerType_UInt16 = integerType_UInt16; + ObjectType = integerType_UInt16; + } + public OneOfTypes(IntegerType integerType_Int16) + { + IntegerType_Int16 = integerType_Int16; + ObjectType = integerType_Int16; + } + public OneOfTypes(IntegerType integerType_UInt32) + { + IntegerType_UInt32 = integerType_UInt32; + ObjectType = integerType_UInt32; + } + public OneOfTypes(IntegerType integerType_Int32) + { + IntegerType_Int32 = integerType_Int32; + ObjectType = integerType_Int32; + } + public OneOfTypes(IntegerType integerType_UInt64) + { + IntegerType_UInt64 = integerType_UInt64; + ObjectType = integerType_UInt64; + } + public OneOfTypes(IntegerType integerType_Int64) + { + IntegerType_Int64 = integerType_Int64; + ObjectType = integerType_Int64; + } +#if NET7_0_OR_GREATER + public OneOfTypes(IntegerType integerType_UInt128) + { + IntegerType_UInt128 = integerType_UInt128; + ObjectType = integerType_UInt128; + } + public OneOfTypes(IntegerType integerType_Int128) + { + IntegerType_Int128 = integerType_Int128; + ObjectType = integerType_Int128; + } +#endif + public OneOfTypes(ReferenceType referenceType) + { + ReferenceType = referenceType; + } + public OneOfTypes(StringType stringType) + { + StringType = stringType; + ObjectType = stringType; + } + public OneOfTypes(ListType listType) + { + ListType = listType; + ObjectType = listType; + } + public OneOfTypes(CompoundType compoundType) + { + CompoundType = compoundType; + ObjectType = compoundType; + } + public OneOfTypes(PD_EnvelopeType pdEnvelopeType) + { + PD_EnvelopeType = pdEnvelopeType; + ObjectType = pdEnvelopeType; + } + + public bool IsEmpty() + { + return getObjectType() == null; + } + public PDL GetDataLength() + { + return getObjectType()?.GetDataLength() ?? new PDL(); + } + public byte[] ParsePayloadToData(DataTree dataTree) + { + return getObjectType().ParsePayloadToData(dataTree); + } + public DataTree ParseDataToPayload(ref byte[] data) + { + return getObjectType().ParseDataToPayload(ref data); + } + private CommonPropertiesForNamed getObjectType() + { + return ObjectType ?? ReferenceType?.ReferencedObject; + } + + public override string ToString() + { + return getObjectType()?.ToString(); + } + } +} \ No newline at end of file diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/PD_EnvelopeType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/PD_EnvelopeType.cs new file mode 100644 index 0000000..70dd548 --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/PD_EnvelopeType.cs @@ -0,0 +1,81 @@ +using RDMSharp.RDM; +using System; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public class PD_EnvelopeType : CommonPropertiesForNamed + { + [JsonPropertyName("name")] + [JsonPropertyOrder(1)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Name { get; } + [JsonPropertyName("displayName")] + [JsonPropertyOrder(2)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string DisplayName { get; } + [JsonPropertyName("notes")] + [JsonPropertyOrder(4)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Notes { get; } + [JsonPropertyName("resources")] + [JsonPropertyOrder(5)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string[] Resources { get; } + + [JsonPropertyName("type")] + [JsonPropertyOrder(3)] + public string Type { get; } + + [JsonPropertyName("length")] + [JsonPropertyOrder(6)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public byte? Length { get; } + + + [JsonConstructor] + public PD_EnvelopeType(string name, + string displayName, + string notes, + string[] resources, + string type, + byte? length) : base() + { + if (!"pdEnvelope".Equals(type)) + throw new ArgumentException($"Argument {nameof(type)} has to be \"pdEnvelope\""); + + Name = name; + DisplayName = displayName; + Notes = notes; + Resources = resources; + Type = type; + Length = length; + } + + public override string ToString() + { + if (Length.HasValue) + return $"PDL: {Length} ({Length:X2}) {base.ToString()}".Trim(); + + return base.ToString(); + } + + public override PDL GetDataLength() + { + if(Length.HasValue) + return new PDL(Length.Value); + + return new PDL(); + } + + public override byte[] ParsePayloadToData(DataTree dataTree) + { + return new byte[0]; + } + + public override DataTree ParseDataToPayload(ref byte[] data) + { + return new DataTree(Name, 0, null); + } + } +} diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/Range.cs b/RDMSharp/Metadata/JSON/OneOfTypes/Range.cs new file mode 100644 index 0000000..cf16b0c --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/Range.cs @@ -0,0 +1,106 @@ +using System; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public readonly struct Range + { + [JsonPropertyName("minimum")] + public readonly T Minimum { get; } + + [JsonPropertyName("maximum")] + public readonly T Maximum { get; } + + [JsonConstructor] + public Range(T minimum, T maximum) + { + Minimum = minimum; + Maximum = maximum; + } + + public bool IsInRange(T value) + { + switch (value) + { + case byte v when Minimum is byte min && Maximum is byte max: + return min <= v && v <= max; + case sbyte v when Minimum is sbyte min && Maximum is sbyte max: + return min <= v && v <= max; + case short v when Minimum is short min && Maximum is short max: + return min <= v && v <= max; + case ushort v when Minimum is ushort min && Maximum is ushort max: + return min <= v && v <= max; + case int v when Minimum is int min && Maximum is int max: + return min <= v && v <= max; + case uint v when Minimum is uint min && Maximum is uint max: + return min <= v && v <= max; + case long v when Minimum is long min && Maximum is long max: + return min <= v && v <= max; + case ulong v when Minimum is ulong min && Maximum is ulong max: + return min <= v && v <= max; +# if NET7_0_OR_GREATER + case Int128 v when Minimum is Int128 min && Maximum is Int128 max: + return min <= v && v <= max; + case UInt128 v when Minimum is UInt128 min && Maximum is UInt128 max: + return min <= v && v <= max; +#endif + } + return false; + } + + public bool IsBelow(T value) + { + switch (value) + { + case byte v when Minimum is byte min: + return min > v; + case sbyte v when Minimum is sbyte min: + return min > v; + case short v when Minimum is short min: + return min > v; + case ushort v when Minimum is ushort min: + return min > v; + case int v when Minimum is int min: + return min > v; + case uint v when Minimum is uint min: + return min > v; + case long v when Minimum is long min: + return min > v; + case ulong v when Minimum is ulong min: + return min > v; +# if NET7_0_OR_GREATER + case Int128 v when Minimum is Int128 min: + return min > v; + case UInt128 v when Minimum is UInt128 min: + return min > v; +#endif + } + return false; + } + + public override string ToString() + { + switch (Minimum) + { + case byte: + case sbyte: + return $"Range: {Minimum:X2} - {Maximum:X2}"; + case short: + case ushort: + return $"Range: {Minimum:X4} - {Maximum:X4}"; + case int: + case uint: + return $"Range: {Minimum:X8} - {Maximum:X8}"; + case long: + case ulong: + return $"Range: {Minimum:X16} - {Maximum:X16}"; +#if NET7_0_OR_GREATER + case Int128: + case UInt128: + return $"Range: {Minimum:X32} - {Maximum:X32}"; +#endif + } + return $"Range: {Minimum} - {Maximum}"; + } + } +} diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/ReferenceType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/ReferenceType.cs new file mode 100644 index 0000000..c3d58ac --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/ReferenceType.cs @@ -0,0 +1,70 @@ +using RDMSharp.RDM; +using System; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public readonly struct ReferenceType + { + [JsonPropertyName("$ref")] + public readonly string URI { get; } + [JsonIgnore(Condition = JsonIgnoreCondition.Always)] + public readonly Command.ECommandDublicte Command { get; } + [JsonIgnore(Condition = JsonIgnoreCondition.Always)] + public readonly ushort Pointer { get; } + [JsonIgnore(Condition = JsonIgnoreCondition.Always)] + public readonly CommonPropertiesForNamed? ReferencedObject { get; } + + [JsonConstructor] + public ReferenceType(string uri) + { + URI = uri; + if (uri.StartsWith("#")) + { + string fragment = uri.Substring(1); + + string[] segments = fragment.Split('/', StringSplitOptions.RemoveEmptyEntries); + + switch (segments[0]) + { + case "get_request": + Command = JSON.Command.ECommandDublicte.GetRequest; + break; + case "get_response": + Command = JSON.Command.ECommandDublicte.GetResponse; + break; + case "set_request": + Command = JSON.Command.ECommandDublicte.SetRequest; + break; + case "set_response": + Command = JSON.Command.ECommandDublicte.SetResponse; + break; + } + Pointer = ushort.Parse(segments[1]); + } + else + throw new ArgumentException($"{nameof(uri)} has to start with \'#\'"); + } + public ReferenceType(string uri, CommonPropertiesForNamed referencedObject) : this(uri) + { + ReferencedObject = referencedObject; + } + public PDL GetDataLength() + { + return ReferencedObject?.GetDataLength() ?? new PDL(); + } + public byte[] ParsePayloadToData(DataTree dataTree) + { + return ReferencedObject.ParsePayloadToData(dataTree); + } + + public DataTree ParseDataToPayload(ref byte[] data) + { + return ReferencedObject.ParseDataToPayload(ref data); + } + public override string ToString() + { + return URI; + } + } +} diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/StringType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/StringType.cs new file mode 100644 index 0000000..978ac03 --- /dev/null +++ b/RDMSharp/Metadata/JSON/OneOfTypes/StringType.cs @@ -0,0 +1,230 @@ +using RDMSharp.RDM; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON.OneOfTypes +{ + public class StringType : CommonPropertiesForNamed + { + [JsonPropertyName("name")] + [JsonPropertyOrder(1)] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Name { get; } + [JsonPropertyName("displayName")] + [JsonPropertyOrder(2)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string DisplayName { get; } + [JsonPropertyName("notes")] + [JsonPropertyOrder(25)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Notes { get; } + [JsonPropertyName("resources")] + [JsonPropertyOrder(5)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string[] Resources { get; } + + [JsonPropertyName("type")] + [JsonPropertyOrder(3)] + public string Type { get; } + [JsonPropertyName("format")] + [JsonPropertyOrder(21)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string Format { get; } + [JsonPropertyName("pattern")] + [JsonPropertyOrder(22)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string Pattern { get; } + [JsonPropertyName("minLength")] + [JsonPropertyOrder(31)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public uint? MinLength { get; } + [JsonPropertyName("maxLength")] + [JsonPropertyOrder(32)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public uint? MaxLength { get; } + [JsonPropertyName("minBytes")] + [JsonPropertyOrder(41)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public uint? MinBytes { get; } + [JsonPropertyName("maxBytes")] + [JsonPropertyOrder(42)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public uint? MaxBytes { get; } + [JsonPropertyName("restrictToASCII")] + [JsonPropertyOrder(51)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? RestrictToASCII { get; } + + + [JsonConstructor] + public StringType(string name, + string displayName, + string notes, + string[] resources, + string type, + string format, + string pattern, + uint? minLength, + uint? maxLength, + uint? minBytes, + uint? maxBytes, + bool? restrictToASCII) + { + if (!"string".Equals(type)) + throw new ArgumentException($"Argument {nameof(type)} has to be \"string\""); + + Name = name; + DisplayName = displayName; + Notes = notes; + Resources = resources; + Type = type; + Format = format; + Pattern = pattern; + MinLength = minLength; + MaxLength = maxLength; + MinBytes = minBytes; + MaxBytes = maxBytes; + RestrictToASCII = restrictToASCII; + } + public StringType( + string name, + string displayName, + string notes, + string format, + string pattern, + uint length, + bool? restrictToASCII = null) : this( + name, + displayName, + notes, + null, + "string", + format, + pattern, + minLength: length, + maxLength: length, + null, + null, + restrictToASCII) + { + } + public override string ToString() + { + return base.ToString(); + } + + public override PDL GetDataLength() + { + uint min = 0; + uint? max = null; + if (MinLength.HasValue) + min = (uint)MinLength.Value; + if (MaxLength.HasValue) + max = (uint)MaxLength.Value; + if (MinBytes.HasValue) + min = (uint)MinBytes.Value; + if (MaxBytes.HasValue) + max = (uint)MaxBytes.Value; + + if (!max.HasValue) + return new PDL(min, PDL.MAX_LENGTH); + + return new PDL(min, max.Value); + } + public override byte[] ParsePayloadToData(DataTree dataTree) + { + if (!string.Equals(dataTree.Name, this.Name)) + throw new ArithmeticException($"The given Name from {nameof(dataTree.Name)}({dataTree.Name}) not match this Name({this.Name})"); + + if (dataTree.Value is string @string) + { + if (MinLength.HasValue && MinLength.Value > @string.Length) + throw new ArithmeticException($"The given String is smaller then {nameof(MinLength)}: {MinLength}"); + if (MaxLength.HasValue && MaxLength.Value < @string.Length) + throw new ArithmeticException($"The given String is larger then {nameof(MaxLength)}: {MaxLength}"); + + Encoding encoder = null; + if (RestrictToASCII == true) + encoder = Encoding.ASCII; + else + encoder = Encoding.UTF8; + + var data = encoder.GetBytes(@string); + + if (MinBytes.HasValue && MinBytes.Value > data.Length) + throw new ArithmeticException($"The given String encoded is smaller then {nameof(MinBytes)}: {MinBytes}"); + if (MaxBytes.HasValue && MaxBytes.Value < data.Length) + throw new ArithmeticException($"The given String encoded is larger then {nameof(MaxBytes)}: {MaxBytes}"); + + return data; + } + + throw new ArithmeticException($"The given Object from {nameof(dataTree.Value)} can't be parsed"); + } + + public override DataTree ParseDataToPayload(ref byte[] data) + { + List issueList = new List(); + if (MaxBytes.HasValue && data.Length > MaxBytes.Value) + issueList.Add(new DataTreeIssue($"Data length exceeds {nameof(MaxBytes)}, the Data has {data.Length}, but {nameof(MaxBytes)} is {MaxBytes}")); + if (MinBytes.HasValue && data.Length < MinBytes.Value) + issueList.Add(new DataTreeIssue($"Data length falls shorts of {nameof(MinBytes)}, the Data has {data.Length}, but {nameof(MinBytes)} is {MinBytes}")); + + string str = null; + byte[] dataBytes = data; + int charLength = 0; + int byteLength = 0; + int takenBytesCount = 0; + if (RestrictToASCII == true) + parse(Encoding.ASCII); + else + parse(Encoding.UTF8); + + void parse(Encoding encoder) + { + str = encoder.GetString(dataBytes); + takenBytesCount = dataBytes.Length; + + string[] strings = str.Split((char)0); + if (strings.Where(s => string.IsNullOrEmpty(s)).Count() > 1) + issueList.Add(new DataTreeIssue("More then one Null-Delimiter")); + if (strings.Skip(1).Any(s => !string.IsNullOrEmpty(s))) + issueList.Add(new DataTreeIssue("Trailing Characters")); + + str = strings.First(); + byteLength = encoder.GetBytes(str).Length; + takenBytesCount = byteLength; + charLength = str.Length; + bool repeatParse = false; + if (MaxLength.HasValue && MaxLength.Value < charLength) + { + charLength = (int)MaxLength.Value; + repeatParse = true; + } + if (MaxBytes.HasValue && MaxBytes.Value < byteLength) + { + byteLength = (int)MaxBytes.Value; + repeatParse = true; + } + if (repeatParse) + { + dataBytes = dataBytes.Take(byteLength).ToArray(); + str = encoder.GetString(dataBytes); + takenBytesCount = dataBytes.Length; + } + + } + + if (MaxLength.HasValue && str.Length > MaxLength.Value) + issueList.Add(new DataTreeIssue($"String length exceeds {nameof(MaxLength)}, the Data has {str.Length}, but {nameof(MaxLength)} is {MaxLength}")); + if (MinLength.HasValue && str.Length < MinLength.Value) + issueList.Add(new DataTreeIssue($"String length falls shorts of {nameof(MinLength)}, the Data has {str.Length}, but {nameof(MinLength)} is {MinLength}")); + + data = data.Skip(takenBytesCount).ToArray(); + return new DataTree(this.Name, 0, str, issueList.Count != 0 ? issueList.ToArray() : null); + } + } +} diff --git a/RDMSharp/Metadata/JSON/SubdeviceRange.cs b/RDMSharp/Metadata/JSON/SubdeviceRange.cs new file mode 100644 index 0000000..bb1260e --- /dev/null +++ b/RDMSharp/Metadata/JSON/SubdeviceRange.cs @@ -0,0 +1,24 @@ +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata.JSON +{ + public readonly struct SubdeviceRange + { + [JsonPropertyName("minimum")] + public readonly ushort Minimum { get; } + + [JsonPropertyName("maximum")] + public readonly ushort Maximum { get; } + + [JsonConstructor] + public SubdeviceRange(ushort minimum, ushort maximum) : this() + { + Minimum = minimum; + Maximum = maximum; + } + public override string ToString() + { + return $"Subdevice Range: {Minimum:X4} - {Maximum:X4}"; + } + } +} diff --git a/RDMSharp/Metadata/JSON/SubdeviceType.cs b/RDMSharp/Metadata/JSON/SubdeviceType.cs new file mode 100644 index 0000000..312cdf3 --- /dev/null +++ b/RDMSharp/Metadata/JSON/SubdeviceType.cs @@ -0,0 +1,27 @@ +using System.Text.Json.Serialization; +using RDMSharp.Metadata.JSON.Converter; + +namespace RDMSharp.Metadata.JSON +{ + [JsonConverter(typeof(SubdeviceTypeConverter))] + public readonly struct SubdeviceType + { + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public readonly ushort? Value { get; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public readonly SubdeviceRange? Range { get; } + public SubdeviceType(ushort value) : this() + { + Value = value; + } + + public SubdeviceType(SubdeviceRange range) : this() + { + Range = range; + } + public override string ToString() + { + return Value?.ToString() ?? Range.ToString(); + } + } +} diff --git a/RDMSharp/Metadata/JSON/SubdevicesForRequests.cs b/RDMSharp/Metadata/JSON/SubdevicesForRequests.cs new file mode 100644 index 0000000..9c80418 --- /dev/null +++ b/RDMSharp/Metadata/JSON/SubdevicesForRequests.cs @@ -0,0 +1,36 @@ +using System.Text.Json.Serialization; +using RDMSharp.Metadata.JSON.Converter; + +namespace RDMSharp.Metadata.JSON +{ + [JsonConverter(typeof(SubdevicesForRequestsConverter))] + public readonly struct SubdevicesForRequests + { + [JsonConverter(typeof(CustomEnumConverter))] + public enum ESubdevicesForRequests + { + [JsonPropertyName("root")] + Root, + [JsonPropertyName("subdevices")] + Subdevices, + [JsonPropertyName("broadcast")] + Broadcast + } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public readonly ESubdevicesForRequests? EnumValue { get; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public readonly SubdeviceType? ObjectValue { get; } + public SubdevicesForRequests(ESubdevicesForRequests enumValue) + { + EnumValue = enumValue; + } + public SubdevicesForRequests(SubdeviceType objectValue) + { + ObjectValue = objectValue; + } + public override string ToString() + { + return EnumValue?.ToString() ?? ObjectValue.ToString(); + } + } +} diff --git a/RDMSharp/Metadata/JSON/SubdevicesForResponses.cs b/RDMSharp/Metadata/JSON/SubdevicesForResponses.cs new file mode 100644 index 0000000..86e6649 --- /dev/null +++ b/RDMSharp/Metadata/JSON/SubdevicesForResponses.cs @@ -0,0 +1,38 @@ +using System.Text.Json.Serialization; +using RDMSharp.Metadata.JSON.Converter; + +namespace RDMSharp.Metadata.JSON +{ + [JsonConverter(typeof(SubdevicesForResponsesConverter))] + public readonly struct SubdevicesForResponses + { + [JsonConverter(typeof(CustomEnumConverter))] + public enum ESubdevicesForResponses + { + [JsonPropertyName("root")] + Root, + [JsonPropertyName("subdevices")] + Subdevices, + [JsonPropertyName("broadcast")] + Broadcast, + [JsonPropertyName("match")] + Match + } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public readonly ESubdevicesForResponses? EnumValue { get; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public readonly SubdeviceType? ObjectValue { get; } + public SubdevicesForResponses(ESubdevicesForResponses enumValue) + { + EnumValue = enumValue; + } + public SubdevicesForResponses(SubdeviceType objectValue) + { + ObjectValue = objectValue; + } + public override string ToString() + { + return EnumValue?.ToString() ?? ObjectValue.ToString(); + } + } +} diff --git a/RDMSharp/Metadata/MetadataBag.cs b/RDMSharp/Metadata/MetadataBag.cs new file mode 100644 index 0000000..c14dc62 --- /dev/null +++ b/RDMSharp/Metadata/MetadataBag.cs @@ -0,0 +1,42 @@ +using System; +using System.IO; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("RDMSharpTests")] + +namespace RDMSharp.Metadata +{ + public readonly struct MetadataBag + { + public readonly string Version; + public readonly string Path; + public readonly string Name; + public readonly string Content; + public readonly bool IsSchema; + public MetadataBag(MetadataVersion metadataVersion) : this(metadataVersion.Version,metadataVersion.Name,metadataVersion.IsSchema, getContent(metadataVersion.Path), metadataVersion.Path) + { + } + public MetadataBag(string version, string name, bool isSchema, string content, string path) + { + Version = version; + Name= name; + IsSchema = isSchema; + Path = path; + Content = content; + } + internal static string getContent(string path) + { + if (string.IsNullOrWhiteSpace(path)) + throw new ArgumentNullException(nameof(path)); + + var assembly = typeof(MetadataFactory).Assembly; + using Stream stream = assembly.GetManifestResourceStream(path); + using StreamReader reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + public override string ToString() + { + return $"{Name} [{Version}]"; + } + } +} diff --git a/RDMSharp/Metadata/MetadataFactory.cs b/RDMSharp/Metadata/MetadataFactory.cs new file mode 100644 index 0000000..f6e69b9 --- /dev/null +++ b/RDMSharp/Metadata/MetadataFactory.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text.Json; +using System.Text.Json.Nodes; +using Json.Schema; +using RDMSharp.Metadata.JSON; +using RDMSharp.Metadata.JSON.OneOfTypes; + +[assembly: InternalsVisibleTo("RDMSharpTests")] + +namespace RDMSharp.Metadata +{ + public static class MetadataFactory + { + private const string SCHEMA_FILE_NAME = "schema.json"; + private const string JSON_ENDING = ".json"; + private static List metadataVersionList; + private static Dictionary> metadataVersionDefinesBagDictionary; + private static ConcurrentDictionary parameterBagDefineCache; + + public static IReadOnlyCollection MetadataVersionList + { + get + { + if (metadataVersionList == null) + { + metadataVersionList = new List(); + metadataVersionList.AddRange(GetResources().Select(r => new MetadataVersion(r))); + } + return metadataVersionList.AsReadOnly(); + } + } + public static string[] GetResources() + { + var assembly = typeof(MetadataFactory).Assembly; + return assembly.GetManifestResourceNames(); + } + private static void fillDefaultMetadataVersionList() + { + metadataVersionList.AddRange(GetResources().Select(r => new MetadataVersion(r))); + + if (metadataVersionDefinesBagDictionary == null) + metadataVersionDefinesBagDictionary = new Dictionary>(); + + var schemaList = GetMetadataSchemaVersions(); + ConcurrentDictionary versionSchemas= new ConcurrentDictionary(); + + foreach (var mv in metadataVersionList.Where(_mv => !_mv.IsSchema)) + { + var schema = schemaList.First(s => s.Version.Equals(mv.Version)); + if(!versionSchemas.TryGetValue(schema.Version, out JsonSchema jsonSchema)) + { + jsonSchema= JsonSchema.FromText(new MetadataBag(schema).Content); + versionSchemas.TryAdd(schema.Version, jsonSchema); + } + MetadataBag metadataBag = new MetadataBag(mv); + var result = jsonSchema.Evaluate(JsonNode.Parse(metadataBag.Content)); + if (result.IsValid) + { + MetadataJSONObjectDefine jsonDefine = JsonSerializer.Deserialize(metadataBag.Content); + if (!metadataVersionDefinesBagDictionary.ContainsKey(schema)) + metadataVersionDefinesBagDictionary.Add(schema, new List()); + + metadataVersionDefinesBagDictionary[schema].Add(jsonDefine); + } + } + } + + public static IReadOnlyCollection GetMetadataSchemaVersions() + { + return MetadataVersionList.Where(r => r.IsSchema).ToList().AsReadOnly(); + } + public static IReadOnlyCollection GetMetadataDefineVersions() + { + return MetadataVersionList.Where(r => !r.IsSchema).ToList().AsReadOnly(); + } + internal static MetadataJSONObjectDefine GetDefine(ParameterBag parameter) + { + try + { + if (parameterBagDefineCache == null) + parameterBagDefineCache = new ConcurrentDictionary(); + + if (parameterBagDefineCache.TryGetValue(parameter, out var define)) + return define; + + define = getDefine(parameter); + if (define != null) + { + parameterBagDefineCache.TryAdd(parameter, define); + return define; + } + } + catch (Exception ex) + { + + } + throw new DefineNotFoundException($"{parameter}"); + } + private static MetadataJSONObjectDefine getDefine(ParameterBag parameter) + { + var version = GetMetadataSchemaVersions().First(); + if (metadataVersionDefinesBagDictionary == null) + fillDefaultMetadataVersionList(); + var possibleDefines = metadataVersionDefinesBagDictionary[version].FindAll(d => d.PID == (ushort)parameter.PID && d.ManufacturerID == parameter.ManufacturerID); + if (possibleDefines.Count == 1) + return possibleDefines[0]; + + if (possibleDefines.Count > 1) + { + MetadataJSONObjectDefine define = possibleDefines.FirstOrDefault(d => d.DeviceModelID == null && d.SoftwareVersionID == null); + if (parameter.DeviceModelID != null) + { + possibleDefines = possibleDefines.Where(d => d.DeviceModelID == parameter.DeviceModelID).ToList(); + if (possibleDefines.Count == 1) + define = possibleDefines[0]; + else if (possibleDefines.Count > 1) + { + define = possibleDefines.FirstOrDefault(d => d.SoftwareVersionID == null) ?? define; + if (parameter.SoftwareVersionID != null) + { + define = possibleDefines.FirstOrDefault(d => d.SoftwareVersionID == parameter.SoftwareVersionID) ?? define; + + if (define == null) + define = possibleDefines.MinBy(d => parameter.SoftwareVersionID - d.SoftwareVersionID); + } + } + } + return possibleDefines.MaxBy(d => d.Version); + } + if (parameter.ManufacturerID == 0) + throw new InvalidOperationException($"{parameter.ManufacturerID} of 0 should lead to exact 1 Define"); + + + + throw new DefineNotFoundException($"{parameter}"); + } + + internal static byte[] ParsePayloadToData(MetadataJSONObjectDefine define, Command.ECommandDublicte commandType, DataTreeBranch payload) + { + define.GetCommand(commandType, out Command? _command); + if (_command is not Command command) + throw new InvalidOperationException(); + + if (command.GetIsEmpty()) + return new byte[0]; + + if (command.SingleField.HasValue && payload.Children.SingleOrDefault() is DataTree dataTree) + return command.SingleField.Value.ParsePayloadToData(dataTree); + + if (command.ListOfFields.Length != 0 && payload.Children is DataTree[] dataTreeArray) + { + if (dataTreeArray.Length != command.ListOfFields.Length) + throw new IndexOutOfRangeException(); + List data = new List(); + for (int i = 0; i < command.ListOfFields.Length; i++) + data.AddRange(command.ListOfFields[i].ParsePayloadToData(dataTreeArray[i])); + return data.ToArray(); + } + + throw new ArithmeticException(); + } + internal static DataTreeBranch ParseDataToPayload(MetadataJSONObjectDefine define, Command.ECommandDublicte commandType, byte[] data) + { + define.GetCommand(commandType, out Command? _command); + if (_command is not Command command) + throw new InvalidOperationException(); + try + { + if (command.GetIsEmpty()) + return DataTreeBranch.Empty; + } + catch(Exception e) + { + + } + + if (command.SingleField.HasValue) + return new DataTreeBranch(define, commandType, command.SingleField.Value.ParseDataToPayload(ref data)); + + if (command.ListOfFields.Length != 0) + { + List tree = new List(); + for (int i = 0; i < command.ListOfFields.Length; i++) + tree.Add(command.ListOfFields[i].ParseDataToPayload(ref data)); + return new DataTreeBranch(define, commandType, tree.ToArray()); + } + + throw new ArithmeticException(); + } + internal static byte[] GetRequestMessageData(ParameterBag parameter, DataTreeBranch payloadData) + { + return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicte.GetRequest, payloadData); + } + internal static byte[] GetResponseMessageData(ParameterBag parameter, DataTreeBranch payloadData) + { + return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicte.GetResponse, payloadData); + } + internal static byte[] SetRequestMessageData(ParameterBag parameter, DataTreeBranch payloadData) + { + return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicte.SetRequest, payloadData); + } + internal static byte[] SetResponseMessageData(ParameterBag parameter, DataTreeBranch payloadData) + { + return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicte.SetResponse, payloadData); + } + + private static List definedDataTreeObjects; + public static IReadOnlyCollection DefinedDataTreeObjects + { + get + { + fillDefinedDataTreeObjects(); + return definedDataTreeObjects; + } + } + + private static void fillDefinedDataTreeObjects() + { + if (definedDataTreeObjects != null) + return; + + definedDataTreeObjects = new List(); + + definedDataTreeObjects.AddRange(Tools.FindClassesWithAttribute()); + } + + public static Type GetDefinedDataTreeObjectType(MetadataJSONObjectDefine define, Command.ECommandDublicte commandType) + { + return GetDefinedDataTreeObjectType((ERDM_Parameter)define.PID, commandType); + } + public static Type GetDefinedDataTreeObjectType(MetadataJSONObjectDefine define, ERDM_Command command) + { + Command.ECommandDublicte commandType = Tools.ConvertCommandDublicteToCommand(command); + return GetDefinedDataTreeObjectType((ERDM_Parameter)define.PID, commandType); + } + public static Type GetDefinedDataTreeObjectType(ERDM_Parameter parameter, ERDM_Command command) + { + Command.ECommandDublicte commandType = Tools.ConvertCommandDublicteToCommand(command); + return GetDefinedDataTreeObjectType(parameter, commandType); + } + public static Type GetDefinedDataTreeObjectType(ERDM_Parameter parameter, Command.ECommandDublicte commandType) + { + return DefinedDataTreeObjects.Where(t => + { + if (t.GetCustomAttributes().Any(attribute => attribute.Parameter == parameter && attribute.Command == commandType)) + return true; + return false; + }).FirstOrDefault(); + } + } +} diff --git a/RDMSharp/Metadata/MetadataJSONObjectDefine.cs b/RDMSharp/Metadata/MetadataJSONObjectDefine.cs new file mode 100644 index 0000000..a3b52b7 --- /dev/null +++ b/RDMSharp/Metadata/MetadataJSONObjectDefine.cs @@ -0,0 +1,224 @@ +using RDMSharp.Metadata.JSON; +using RDMSharp.Metadata.JSON.OneOfTypes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace RDMSharp.Metadata +{ + public class MetadataJSONObjectDefine + { + [JsonPropertyName("name")] + public string Name { get; } + + [JsonPropertyName("displayName")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? DisplayName { get; } + + [JsonPropertyName("notes")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Notes { get; } + [JsonPropertyName("manufacturer_id")] + public ushort ManufacturerID { get; } + + [JsonPropertyName("device_model_id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ushort? DeviceModelID { get; } + + [JsonPropertyName("software_version_id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public uint? SoftwareVersionID { get; } + + [JsonPropertyName("pid")] + public ushort PID { get; } + + [JsonPropertyName("version")] + public ushort Version { get; } + + [JsonPropertyName("get_request_subdevice_range")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(11)] + public SubdevicesForRequests[]? GetRequestSubdeviceRange { get; } + [JsonPropertyName("get_response_subdevice_range")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(13)] + public SubdevicesForResponses[]? GetResponseSubdeviceRange { get; } + [JsonPropertyName("set_request_subdevice_range")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(15)] + public SubdevicesForRequests[]? SetRequestsSubdeviceRange { get; } + [JsonPropertyName("set_response_subdevice_range")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(17)] + public SubdevicesForResponses[]? SetResponseSubdeviceRange { get; } + + [JsonPropertyName("get_request")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(12)] + public Command? GetRequest { get; } + [JsonPropertyName("get_response")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(14)] + public Command? GetResponse { get; } + [JsonPropertyName("set_request")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(16)] + public Command? SetRequest { get; } + [JsonPropertyName("set_response")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(18)] + public Command? SetResponse { get; } + + [JsonConstructor] + public MetadataJSONObjectDefine( + string name, + string? displayName, + string? notes, + ushort manufacturerID, + ushort? deviceModelID, + uint? softwareVersionID, + ushort pID, + ushort version, + SubdevicesForRequests[]? getRequestSubdeviceRange, + SubdevicesForResponses[]? getResponseSubdeviceRange, + SubdevicesForRequests[]? setRequestsSubdeviceRange, + SubdevicesForResponses[]? setResponseSubdeviceRange, + Command? getRequest, + Command? getResponse, + Command? setRequest, + Command? setResponse) + { + if (getRequest.HasValue ^ getResponse.HasValue) + throw new JsonException($"Both {nameof(getRequest)} & {nameof(getResponse)} and have to be defined in {name}"); + + if (setRequest.HasValue ^ setResponse.HasValue) + throw new JsonException($"Both {nameof(setRequest)} & {nameof(setResponse)} and have to be defined in {name}"); + + Name = name; + DisplayName = displayName; + Notes = notes; + ManufacturerID = manufacturerID; + DeviceModelID = deviceModelID; + SoftwareVersionID = softwareVersionID; + PID = pID; + Version = version; + + GetRequestSubdeviceRange = getRequestSubdeviceRange; + GetResponseSubdeviceRange = getResponseSubdeviceRange; + SetRequestsSubdeviceRange = setRequestsSubdeviceRange; + SetResponseSubdeviceRange = setResponseSubdeviceRange; + + GetRequest = getRequest; + GetResponse = getResponse; + SetRequest = setRequest; + SetResponse = setResponse; + + if (getRequest.HasValue) + GetRequest = setReferenceObjects(getRequest.Value); + if (getResponse.HasValue) + GetResponse = setReferenceObjects(getResponse.Value); + if (setRequest.HasValue) + SetRequest = setReferenceObjects(setRequest.Value); + if (setResponse.HasValue) + SetResponse = setReferenceObjects(setResponse.Value); + + + Command setReferenceObjects(Command command) + { + if (command.SingleField.HasValue) + { + var result= setReferenceObjects(command.SingleField.Value); + if (!result.Equals(command.SingleField.Value)) + return new Command(result); + } + + if (command.ListOfFields != null) + { + List listOfFields = new List(); + foreach (OneOfTypes oneOf in command.ListOfFields) + { + var result = setReferenceObjects(oneOf); + if (!result.Equals(oneOf)) + listOfFields.Add(result); + else + listOfFields.Add(oneOf); + } + if (!listOfFields.SequenceEqual(command.ListOfFields)) + return new Command(listOfFields.ToArray()); + } + + return command; + + OneOfTypes setReferenceObjects(OneOfTypes oneOf) + { + if (!oneOf.ReferenceType.HasValue) + return oneOf; + + ReferenceType reference = oneOf.ReferenceType.Value; + + switch (reference.Command) + { + case Command.ECommandDublicte.GetRequest: + if (!getRequest.HasValue) + throw new JsonException($"The Referenced Command ({reference.Command.ToString()})is not defined"); + reference = new ReferenceType(reference.URI, getRequest.Value.ListOfFields[reference.Pointer].ObjectType); + break; + + case Command.ECommandDublicte.GetResponse: + if (!getResponse.HasValue) + throw new JsonException($"The Referenced Command ({reference.Command.ToString()})is not defined"); + reference = new ReferenceType(reference.URI, getResponse.Value.ListOfFields[reference.Pointer].ObjectType); + break; + + case Command.ECommandDublicte.SetRequest: + if (!setRequest.HasValue) + throw new JsonException($"The Referenced Command ({reference.Command.ToString()})is not defined"); + reference = new ReferenceType(reference.URI, setRequest.Value.ListOfFields[reference.Pointer].ObjectType); + break; + + case Command.ECommandDublicte.SetResponse: + if (!setResponse.HasValue) + throw new JsonException($"The Referenced Command ({reference.Command.ToString()})is not defined"); + reference = new ReferenceType(reference.URI, setResponse.Value.ListOfFields[reference.Pointer].ObjectType); + break; + } + return new OneOfTypes(reference); + } + } + } + + public void GetCommand(Command.ECommandDublicte eCommand,out Command? command) + { + command = null; + switch (eCommand) + { + case Command.ECommandDublicte.GetRequest: + command = GetRequest.Value; + break; + case Command.ECommandDublicte.GetResponse: + command = GetResponse.Value; + break; + case Command.ECommandDublicte.SetRequest: + command = SetRequest.Value; + break; + case Command.ECommandDublicte.SetResponse: + command = SetResponse.Value; + break; + } + if (command.HasValue) + if (command.Value.EnumValue.HasValue) + GetCommand(command.Value.EnumValue.Value, out command); + + } + + public override string ToString() + { + if (!string.IsNullOrWhiteSpace(Notes)) + return $"{ManufacturerID:X4} {PID:X4} {Name} ({Notes})"; + + return $"{ManufacturerID:X4} {PID:X4} {Name}"; + } + } +} diff --git a/RDMSharp/Metadata/MetadataVersion.cs b/RDMSharp/Metadata/MetadataVersion.cs new file mode 100644 index 0000000..1b3d237 --- /dev/null +++ b/RDMSharp/Metadata/MetadataVersion.cs @@ -0,0 +1,73 @@ +using System; +using System.Runtime.CompilerServices; +using System.Text.RegularExpressions; + +[assembly: InternalsVisibleTo("RDMSharpTests")] + +namespace RDMSharp.Metadata +{ + public readonly struct MetadataVersion + { + public readonly string Version; + public readonly string Path; + public readonly string Name; + public readonly bool IsSchema; + public MetadataVersion(string path) : this(getVersion(path), getName(path), getIsSchema(path), path) + { + } + public MetadataVersion(string version, string name, bool isSchema, string path) + { + Version = version; + Path = path; + Name = name; + IsSchema = isSchema; + } + internal static string getVersion(string path) + { + if (string.IsNullOrWhiteSpace(path)) + throw new ArgumentNullException(nameof(path)); + + if (!path.ToLower().EndsWith(".json")) + throw new ArgumentException($"The given Paths should end with .json ({nameof(path)})"); + + string pattern = @"_(\d+)\._(\d+)\._(\d+)"; + var match = Regex.Match(path, pattern); + + if (match.Success) + { + return match.Value.Replace("_", ""); + } + else + throw new FormatException($"Can't extract Version from Path: {path}"); + } + internal static bool getIsSchema(string path) + { + if (string.IsNullOrWhiteSpace(path)) + throw new ArgumentNullException(nameof(path)); + + if (!path.ToLower().EndsWith(".json")) + throw new ArgumentException($"The given Paths should end with .json ({nameof(path)})"); + + return path.ToLower().EndsWith("schema.json"); + } + internal static string getName(string path) + { + if (string.IsNullOrWhiteSpace(path)) + throw new ArgumentNullException(nameof(path)); + + string pattern = @"[^\.]+\.[json]+$"; + var match = Regex.Match(path, pattern); + + if (match.Success) + { + return match.Value; + } + else + throw new FormatException($"The given Paths should end with .json ({nameof(path)})"); + } + public override string ToString() + { + return $"{Name} [{Version}]"; + } + } +} diff --git a/RDMSharp/Metadata/ParameterBag.cs b/RDMSharp/Metadata/ParameterBag.cs new file mode 100644 index 0000000..98ad4eb --- /dev/null +++ b/RDMSharp/Metadata/ParameterBag.cs @@ -0,0 +1,77 @@ +using System; + +namespace RDMSharp.Metadata +{ + public readonly struct ParameterBag : IEquatable + { + public readonly ERDM_Parameter PID { get; } + public readonly ushort ManufacturerID { get; } + public readonly ushort? DeviceModelID { get; } + public readonly uint? SoftwareVersionID { get; } + public ParameterBag() + { + throw new NotSupportedException("Its not allowed to have an default of this Type"); + } + public ParameterBag(ERDM_Parameter pid, ushort manufacturerID = 0, ushort? deviceModelID = null, uint? softwareVersionID = null) + { + if ((ushort)pid >= 0x8000) + { + if (manufacturerID == 0) + throw new ArgumentNullException($"{nameof(pid)} in range 0x8000 -0xFFFF requires {nameof(manufacturerID)} != 0"); + } + else + { + manufacturerID = 0; + deviceModelID = null; + softwareVersionID = null; + } + + PID = pid; + ManufacturerID = manufacturerID; + DeviceModelID = deviceModelID; + SoftwareVersionID = softwareVersionID; + } + public override string ToString() + { + if (ManufacturerID != 0) + { + if (DeviceModelID != null) + { + if (SoftwareVersionID != null) + return $"{PID} ManufacturerID: {ManufacturerID}, DeviceModelID: {DeviceModelID}, SoftwareVersionID: {SoftwareVersionID}"; + return $"{PID} ManufacturerID: {ManufacturerID}, DeviceModelID: {DeviceModelID}"; + } + return $"{PID} ManufacturerID: {ManufacturerID}"; + } + return $"{PID}"; + } + + public override bool Equals(object obj) + { + return obj is ParameterBag bag && Equals(bag); + } + + public bool Equals(ParameterBag other) + { + return PID == other.PID && + ManufacturerID == other.ManufacturerID && + DeviceModelID == other.DeviceModelID && + SoftwareVersionID == other.SoftwareVersionID; + } + + public override int GetHashCode() + { + return HashCode.Combine(PID, ManufacturerID, DeviceModelID, SoftwareVersionID); + } + + public static bool operator ==(ParameterBag left, ParameterBag right) + { + return left.Equals(right); + } + + public static bool operator !=(ParameterBag left, ParameterBag right) + { + return !(left == right); + } + } +} diff --git a/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EBatteryExtension.cs b/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EBatteryExtension.cs index 4f88650..3d6412b 100644 --- a/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EBatteryExtension.cs +++ b/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EBatteryExtension.cs @@ -1,5 +1,10 @@ -namespace RDMSharp.ParameterWrapper.SGM -{ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp.ParameterWrapper.SGM +{ + [DataTreeEnum(EManufacturer.SGM_Technology_For_Lighting_SPA, (ERDM_Parameter)(ushort)EParameter.BATTERY_EXTENSION, Command.ECommandDublicte.GetResponse,"")] + [DataTreeEnum(EManufacturer.SGM_Technology_For_Lighting_SPA, (ERDM_Parameter)(ushort)EParameter.BATTERY_EXTENSION, Command.ECommandDublicte.SetRequest,"")] public enum EBatteryExtension : byte { DISABLED = 0, diff --git a/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EDimMode.cs b/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EDimMode.cs index 378cea1..91eb8e9 100644 --- a/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EDimMode.cs +++ b/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EDimMode.cs @@ -1,5 +1,10 @@ -namespace RDMSharp.ParameterWrapper.SGM -{ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp.ParameterWrapper.SGM +{ + [DataTreeEnum(EManufacturer.SGM_Technology_For_Lighting_SPA, (ERDM_Parameter)(ushort)EParameter.DIM_MODE, Command.ECommandDublicte.GetResponse,"")] + [DataTreeEnum(EManufacturer.SGM_Technology_For_Lighting_SPA, (ERDM_Parameter)(ushort)EParameter.DIM_MODE, Command.ECommandDublicte.SetRequest,"")] public enum EDimMode : byte { STANDARD = 0, diff --git a/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EDimmingCurve.cs b/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EDimmingCurve.cs index 0cbcabc..a164020 100644 --- a/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EDimmingCurve.cs +++ b/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EDimmingCurve.cs @@ -1,5 +1,10 @@ -namespace RDMSharp.ParameterWrapper.SGM -{ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp.ParameterWrapper.SGM +{ + [DataTreeEnum(EManufacturer.SGM_Technology_For_Lighting_SPA, (ERDM_Parameter)(ushort)EParameter.DIMMING_CURVE, Command.ECommandDublicte.GetResponse,"")] + [DataTreeEnum(EManufacturer.SGM_Technology_For_Lighting_SPA, (ERDM_Parameter)(ushort)EParameter.DIMMING_CURVE, Command.ECommandDublicte.SetRequest,"")] public enum EDimmingCurve : byte { RAW = 0, diff --git a/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EFanMode.cs b/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EFanMode.cs index c91add8..55837e7 100644 --- a/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EFanMode.cs +++ b/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EFanMode.cs @@ -1,5 +1,10 @@ -namespace RDMSharp.ParameterWrapper.SGM -{ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp.ParameterWrapper.SGM +{ + [DataTreeEnum(EManufacturer.SGM_Technology_For_Lighting_SPA, (ERDM_Parameter)(ushort)EParameter.FAN_MODE, Command.ECommandDublicte.GetResponse,"")] + [DataTreeEnum(EManufacturer.SGM_Technology_For_Lighting_SPA, (ERDM_Parameter)(ushort)EParameter.FAN_MODE, Command.ECommandDublicte.SetRequest,"")] public enum EFanMode : byte { AUTO = 0, diff --git a/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EInvertPixelOrder.cs b/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EInvertPixelOrder.cs index 8f6ae96..b400d5e 100644 --- a/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EInvertPixelOrder.cs +++ b/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/EInvertPixelOrder.cs @@ -1,5 +1,10 @@ -namespace RDMSharp.ParameterWrapper.SGM -{ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp.ParameterWrapper.SGM +{ + [DataTreeEnum(EManufacturer.SGM_Technology_For_Lighting_SPA, (ERDM_Parameter)(ushort)EParameter.INVERT_PIXEL_ORDER, Command.ECommandDublicte.GetResponse,"")] + [DataTreeEnum(EManufacturer.SGM_Technology_For_Lighting_SPA, (ERDM_Parameter)(ushort)EParameter.INVERT_PIXEL_ORDER, Command.ECommandDublicte.SetRequest,"")] public enum EInvertPixelOrder : byte { STANDARD = 0, diff --git a/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/RefreshRate.cs b/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/RefreshRate.cs index b28f4ca..a541e9c 100644 --- a/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/RefreshRate.cs +++ b/RDMSharp/ParameterWrapper/Catalogue/Manufacturer/SGM/RefreshRate.cs @@ -1,7 +1,12 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; namespace RDMSharp.ParameterWrapper.SGM -{ +{ + [DataTreeObject(EManufacturer.SGM_Technology_For_Lighting_SPA, (ERDM_Parameter)(ushort)EParameter.REFRESH_RATE, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(EManufacturer.SGM_Technology_For_Lighting_SPA, (ERDM_Parameter)(ushort)EParameter.REFRESH_RATE, Command.ECommandDublicte.SetRequest)] + public readonly struct RefreshRate : IEquatable { public const uint FREQUENCY_MULTIPLYER = 197647; diff --git a/RDMSharp/ParameterWrapper/RDMParameterWrapperCatalogueManager.cs b/RDMSharp/ParameterWrapper/RDMParameterWrapperCatalogueManager.cs deleted file mode 100644 index 5d5048d..0000000 --- a/RDMSharp/ParameterWrapper/RDMParameterWrapperCatalogueManager.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; - -namespace RDMSharp.ParameterWrapper -{ - public sealed class RDMParameterWrapperCatalogueManager - { - private static RDMParameterWrapperCatalogueManager instance; - - public static RDMParameterWrapperCatalogueManager GetInstance() - { - if (instance == null) - instance = new RDMParameterWrapperCatalogueManager(); - - return instance; - } - private HashSet parameterWrappers = new HashSet(); - public ReadOnlyCollection ParameterWrappers - { - get - { - return this.parameterWrappers.ToList().AsReadOnly(); - } - } - private RDMParameterWrapperCatalogueManager() - { - var type = typeof(IRDMParameterWrapper); - var types = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(s => s.GetTypes()) - .Where(p => type.IsAssignableFrom(p) && !p.IsAbstract && !p.IsInterface); - foreach (Type t in types) - this.RegisterParameterWrapper(t); - } - public IRDMParameterWrapper GetRDMParameterWrapperByID(ERDM_Parameter parameter, EManufacturer? manufacturer = null, ushort? deviceModelId = null) - { - if (!manufacturer.HasValue && !deviceModelId.HasValue) - return parameterWrappers.SingleOrDefault(pw => pw.Parameter == parameter); - - if (manufacturer.HasValue) - { - var wrappers = parameterWrappers.OfType().Where(pw => pw.Manufacturer == manufacturer && pw.Parameter == parameter); - if (deviceModelId.HasValue) - return wrappers.OfType().SingleOrDefault(pw => pw.DeviceModelIds.Contains(deviceModelId.Value)); - else - return wrappers.SingleOrDefault(); - } - - return null; - } - - public void RegisterParameterWrapper(Type type) - { - if (type.GetConstructor(Type.EmptyTypes) == null) - return; - if (typeof(IRDMParameterWrapper).IsAssignableFrom(type)) - this.parameterWrappers.Add((IRDMParameterWrapper)Activator.CreateInstance(type)); - } - - public object ParameterDataObjectFromMessage(RDMMessage message) - { - var wrapper = parameterWrappers.FirstOrDefault(pw => pw.Parameter == message.Parameter); - if (wrapper == null) - return null; - - switch (message.Command) - { - case ERDM_Command.GET_COMMAND when wrapper is IRDMGetParameterWrapperRequest @getRequest: - return getRequest.GetRequestParameterDataToObject(message.ParameterData); - - case ERDM_Command.GET_COMMAND_RESPONSE when wrapper is IRDMGetParameterWrapperResponse @getResponse: - return @getResponse.GetResponseParameterDataToObject(message.ParameterData); - - case ERDM_Command.SET_COMMAND when wrapper is IRDMSetParameterWrapperRequest @setRequest: - return @setRequest.SetRequestParameterDataToObject(message.ParameterData); - - case ERDM_Command.SET_COMMAND_RESPONSE when wrapper is IRDMSetParameterWrapperResponse @setResponse: - return @setResponse.SetResponseParameterDataToObject(message.ParameterData); - } - - return null; - } - } -} diff --git a/RDMSharp/RDM/AbstractSendReceivePipeline.cs b/RDMSharp/RDM/AbstractSendReceivePipeline.cs new file mode 100644 index 0000000..5e02022 --- /dev/null +++ b/RDMSharp/RDM/AbstractSendReceivePipeline.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace RDMSharp.RDM +{ + public abstract class AbstractSendReceivePipeline + { + public abstract Task SendMesage(RDMMessage message); + public abstract Task ReceiveMesage(RDMMessage message); + } +} diff --git a/RDMSharp/RDM/AsyncRDMRequestHelper.cs b/RDMSharp/RDM/AsyncRDMRequestHelper.cs index 9041b17..109da03 100644 --- a/RDMSharp/RDM/AsyncRDMRequestHelper.cs +++ b/RDMSharp/RDM/AsyncRDMRequestHelper.cs @@ -33,7 +33,7 @@ public void Dispose() this.IsDisposing= false; } - public bool ReceiveMethode(RDMMessage rdmMessage) + public bool ReceiveMessage(RDMMessage rdmMessage) { if (this.IsDisposing || this.IsDisposed) return false; @@ -67,7 +67,7 @@ public bool ReceiveMethode(RDMMessage rdmMessage) } - public async Task RequestParameter(RDMMessage requerst) + public async Task RequestMessage(RDMMessage requerst) { try { diff --git a/RDMSharp/RDM/Device/AbstractGeneratedRDMDevice.cs b/RDMSharp/RDM/Device/AbstractGeneratedRDMDevice.cs index 819fc6a..e534632 100644 --- a/RDMSharp/RDM/Device/AbstractGeneratedRDMDevice.cs +++ b/RDMSharp/RDM/Device/AbstractGeneratedRDMDevice.cs @@ -1,7 +1,9 @@ using Microsoft.Extensions.Logging; +using RDMSharp.Metadata; using RDMSharp.ParameterWrapper; using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; namespace RDMSharp @@ -123,6 +125,7 @@ protected AbstractGeneratedRDMDevice(UID uid, ERDM_Parameter[] parameters, strin #region Parameters var _params = parameters.ToList(); _params.Add(ERDM_Parameter.DEVICE_INFO); + _params.Add(ERDM_Parameter.SUPPORTED_PARAMETERS); _params.Add(ERDM_Parameter.DEVICE_LABEL); _params.Add(ERDM_Parameter.DEVICE_MODEL_DESCRIPTION); _params.Add(ERDM_Parameter.MANUFACTURER_LABEL); @@ -145,6 +148,7 @@ protected AbstractGeneratedRDMDevice(UID uid, ERDM_Parameter[] parameters, strin } Parameters = _params.Distinct().ToArray(); + trySetParameter(ERDM_Parameter.SUPPORTED_PARAMETERS, Parameters); #endregion #region ManufacturerLabel @@ -204,10 +208,14 @@ protected AbstractGeneratedRDMDevice(UID uid, ERDM_Parameter[] parameters, strin if (Sensors.Length != 0) { var sensorDef = new ConcurrentDictionary(); + var sensorValue = new ConcurrentDictionary(); foreach (var sensor in Sensors) { if (!sensorDef.TryAdd(sensor.SensorId, (RDMSensorDefinition)sensor)) - throw new Exception($"{sensor.SensorId} already used as {nameof(sensor.SensorId)}"); + throw new Exception($"{sensor.SensorId} already used as {nameof(RDMSensorDefinition)}"); + + if (!sensorValue.TryAdd(sensor.SensorId, (RDMSensorValue)sensor)) + throw new Exception($"{sensor.SensorId} already used as {nameof(RDMSensorValue)}"); SetGeneratedSensorDescription((RDMSensorDefinition)sensor); SetGeneratedSensorValue((RDMSensorValue)sensor); @@ -231,12 +239,15 @@ protected AbstractGeneratedRDMDevice(UID uid, ERDM_Parameter[] parameters, strin case nameof(Sensor.HighestValue): case nameof(Sensor.RecordedValue): SetGeneratedSensorValue((RDMSensorValue)sensor); + sensorValue.AddOrUpdate(sensor.SensorId, (RDMSensorValue)sensor, (o1, o2) => (RDMSensorValue)sensor); + SetGeneratedParameterValue(ERDM_Parameter.SENSOR_VALUE, sensorValue); break; } }; } - trySetParameter(ERDM_Parameter.SENSOR_DEFINITION, sensorDef); + SetGeneratedParameterValue(ERDM_Parameter.SENSOR_DEFINITION, sensorDef); + SetGeneratedParameterValue(ERDM_Parameter.SENSOR_VALUE, sensorValue); } } #endregion @@ -256,28 +267,24 @@ private void updateDeviceInfo() ProductCategoryCoarse, ProductCategoryFine, SoftwareVersionID, + dmx512Footprint: Personalities.FirstOrDefault(p => p.ID == currentPersonality)?.SlotCount ?? 0, dmx512CurrentPersonality: currentPersonality, dmx512NumberOfPersonalities: (byte)(Personalities?.Length ?? 0), dmx512StartAddress: dmxAddress, sensorCount: (byte)(Sensors?.Length ?? 0)); } - private bool trySetParameter(ERDM_Parameter parameter, object value) + protected bool trySetParameter(ERDM_Parameter parameter, object value) { if (!this.Parameters.Contains(parameter)) throw new NotSupportedException($"The Parameter: {parameter}, is not Supported"); - switch (pmManager.GetRDMParameterWrapperByID(parameter)) - { - case IRDMSetParameterWrapperResponse setParameterWrapperResponse: - if (setParameterWrapperResponse.SetResponseType != value.GetType()) - throw new NotSupportedException($"The Type of {value.GetType()} is not supported as Response for Parameter: {parameter}, the only supported Type is {setParameterWrapperResponse.SetResponseType}"); - break; - } + base.SetGeneratedParameterValue(parameter, value); return true; } public bool TrySetParameter(ERDM_Parameter parameter, object value, bool throwException = true) { + switch (parameter) { case ERDM_Parameter.DMX_START_ADDRESS: @@ -300,12 +307,28 @@ public bool TrySetParameter(ERDM_Parameter parameter, object value, bool throwEx throw new NotSupportedException($"The Protocoll not allow to set the Parameter: {parameter}"); return false; } - switch (pmManager.GetRDMParameterWrapperByID(parameter)) + + var parameterBag = new ParameterBag(parameter, UID.ManufacturerID, DeviceInfo?.DeviceModelId, DeviceInfo?.SoftwareVersionId); + var define = MetadataFactory.GetDefine(parameterBag); + if (define != null) { - case IRDMDescriptionParameterWrapper descriptionParameterWrapper: - if (throwException) - throw new NotSupportedException($"You have no permission to set the Parameter: {parameter}, use the public Propertys to set them"); + try + { + if (!define.SetRequest.HasValue) + throw new NotSupportedException($"The Protocoll not allow to set the Parameter: {parameter}"); + else + { + byte[] data = MetadataFactory.ParsePayloadToData(define, Metadata.JSON.Command.ECommandDublicte.SetRequest, DataTreeBranch.FromObject(value, null, parameterBag, ERDM_Command.SET_COMMAND)); + var obj = MetadataFactory.ParseDataToPayload(define, Metadata.JSON.Command.ECommandDublicte.SetRequest, data); + if (!object.Equals(value, obj)) + return false; + } + } + catch (Exception e) + { + Logger?.LogError(e, string.Empty); return false; + } } return this.trySetParameter(parameter, value); @@ -316,6 +339,7 @@ protected sealed override void OnPropertyChanged(string property) { case nameof(DeviceInfo): trySetParameter(ERDM_Parameter.DEVICE_INFO, this.DeviceInfo); + trySetParameter(ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL, this.DeviceInfo.SoftwareVersionId); break; case nameof(DeviceModelDescription): trySetParameter(ERDM_Parameter.DEVICE_MODEL_DESCRIPTION, this.DeviceModelDescription); @@ -326,15 +350,16 @@ protected sealed override void OnPropertyChanged(string property) case nameof(CurrentPersonality): trySetParameter(ERDM_Parameter.DMX_PERSONALITY, new RDMDMXPersonality(this.currentPersonality, (byte)(Personalities?.Length ?? 0))); - var slotInfos = new ConcurrentDictionary(); + var slots = Personalities.First(p => p.ID == this.currentPersonality).Slots.Count; + var slotInfos = new RDMSlotInfo[slots]; var slotDesc = new ConcurrentDictionary(); - var slotDefault = new ConcurrentDictionary(); + var slotDefault = new RDMDefaultSlotValue[slots]; foreach (var s in Personalities.First(p => p.ID == this.currentPersonality).Slots) { Slot slot = s.Value; - slotInfos.TryAdd(slot.SlotId, new RDMSlotInfo(slot.SlotId, slot.Type, slot.Category)); + slotInfos[slot.SlotId] = new RDMSlotInfo(slot.SlotId, slot.Type, slot.Category); slotDesc.TryAdd(slot.SlotId, new RDMSlotDescription(slot.SlotId, slot.Description)); - slotDefault.TryAdd(slot.SlotId, new RDMDefaultSlotValue(slot.SlotId, slot.DefaultValue)); + slotDefault[slot.SlotId] = new RDMDefaultSlotValue(slot.SlotId, slot.DefaultValue); } trySetParameter(ERDM_Parameter.SLOT_INFO, slotInfos); trySetParameter(ERDM_Parameter.SLOT_DESCRIPTION, slotDesc); diff --git a/RDMSharp/RDM/Device/AbstractRDMCache.cs b/RDMSharp/RDM/Device/AbstractRDMCache.cs new file mode 100644 index 0000000..7611f60 --- /dev/null +++ b/RDMSharp/RDM/Device/AbstractRDMCache.cs @@ -0,0 +1,150 @@ +using RDMSharp.Metadata; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace RDMSharp +{ + public abstract class AbstractRDMCache : IDisposable + { + protected bool IsDisposed { get; private set; } + protected bool IsDisposing { get; private set; } + protected ConcurrentDictionary parameterValuesDataTreeBranch { get; private set; } = new ConcurrentDictionary(); + protected ConcurrentDictionary parameterValuesDependeciePropertyBag { get; private set; } = new ConcurrentDictionary(); + + protected ConcurrentDictionary parameterValues { get; private set; } = new ConcurrentDictionary(); + public virtual IReadOnlyDictionary ParameterValues + { + get { return this.parameterValues?.AsReadOnly(); } + } + + protected AsyncRDMRequestHelper asyncRDMRequestHelper; + + public AbstractRDMCache() + { + + } + + + protected void updateParameterValuesDependeciePropertyBag(ERDM_Parameter parameter, DataTreeBranch dataTreeBranch) + { + object obj = dataTreeBranch.ParsedObject; + if (obj == null) + return; + + foreach (var p in obj.GetType().GetProperties().Where(p => p.GetCustomAttributes().Any()).ToList()) + { + object value = p.GetValue(obj); + foreach (var item in p.GetCustomAttributes()) + parameterValuesDependeciePropertyBag.AddOrUpdate(item.Bag, value, (o1, o2) => value); + } + } + + protected void updateParameterValuesDataTreeBranch(ParameterDataCacheBag bag, DataTreeBranch dataTreeBranch) + { + parameterValuesDataTreeBranch.AddOrUpdate(bag, dataTreeBranch, (o1, o2) => dataTreeBranch); + + object valueToStore = dataTreeBranch.ParsedObject ?? dataTreeBranch; + if (bag.Index == null) + this.parameterValues.AddOrUpdate(bag.Parameter, valueToStore, (o1, o2) => valueToStore); + else + { + this.parameterValues.AddOrUpdate(bag.Parameter, + (o1) => + //Add + { + ConcurrentDictionary dict = new ConcurrentDictionary(); + dict.AddOrUpdate(bag.Index, valueToStore, (o1, o2) => valueToStore); + return dict; + }, + (o1, o2) => + // Update + { + ConcurrentDictionary dict = (ConcurrentDictionary)o2; + dict.AddOrUpdate(bag.Index, valueToStore, (o1, o2) => valueToStore); + return dict; + }); + + + } + } + + protected async Task runPeerToPeerProcess(PeerToPeerProcess ptpProcess) + { + await ptpProcess?.Run(asyncRDMRequestHelper); + } + + protected async Task requestParameterWithEmptyPayload(ParameterBag parameterBag, MetadataJSONObjectDefine define, UID uid, SubDevice subDevice) + { + PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.GET_COMMAND, uid, subDevice, parameterBag); + await runPeerToPeerProcess(ptpProcess); + if (!ptpProcess.ResponsePayloadObject.IsUnset) + { + updateParameterValuesDependeciePropertyBag(parameterBag.PID, ptpProcess.ResponsePayloadObject); + updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(parameterBag.PID), ptpProcess.ResponsePayloadObject); + } + } + protected async Task requestParameterWithPayload(ParameterBag parameterBag, MetadataJSONObjectDefine define, UID uid, SubDevice subDevice) + { + var req = define.GetRequest.Value.GetRequiredProperties(); + if (req.Length == 1 && req[0] is Metadata.JSON.OneOfTypes.IIntegerType intType) + { + try + { + string name = intType.Name; + + IComparable dependecyValue = (IComparable)parameterValuesDependeciePropertyBag.FirstOrDefault(bag => bag.Key.Parameter == parameterBag.PID && bag.Key.Command == Metadata.JSON.Command.ECommandDublicte.GetRequest && string.Equals(bag.Key.Name, name)).Value; + + object i = intType.GetMinimum(); + object max = intType.GetMaximum(); + object count = Convert.ChangeType(0, i.GetType()); + while (dependecyValue.CompareTo(count) > 0) + { + if (!intType.IsInRange(i)) + continue; + + if (((IComparable)max).CompareTo(i) == -1) + return; + + DataTreeBranch dataTreeBranch = new DataTreeBranch(new DataTree(name, 0, i)); + PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.GET_COMMAND, uid, subDevice, parameterBag, dataTreeBranch); + await runPeerToPeerProcess(ptpProcess); + if (!ptpProcess.ResponsePayloadObject.IsUnset) + updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(parameterBag.PID, i), ptpProcess.ResponsePayloadObject); + + i = intType.IncrementJumpRange(i); + count = intType.Increment(count); + } + } + catch (Exception e) + { + + } + } + } + + + public void Dispose() + { + if (this.IsDisposed || this.IsDisposing) + return; + + this.IsDisposing = true; + + this.asyncRDMRequestHelper?.Dispose(); + this.asyncRDMRequestHelper = null; + + this.parameterValues.Clear(); + this.parameterValues = null; + this.parameterValuesDataTreeBranch.Clear(); + this.parameterValuesDataTreeBranch = null; + this.parameterValuesDependeciePropertyBag.Clear(); + this.parameterValuesDependeciePropertyBag = null; + this.IsDisposed = true; + this.IsDisposing = false; + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/AbstractRDMDevice.cs b/RDMSharp/RDM/Device/AbstractRDMDevice.cs index c2453fc..91fe25c 100644 --- a/RDMSharp/RDM/Device/AbstractRDMDevice.cs +++ b/RDMSharp/RDM/Device/AbstractRDMDevice.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Logging; +using RDMSharp.Metadata; using RDMSharp.ParameterWrapper; using System; using System.Collections.Concurrent; @@ -9,34 +10,93 @@ namespace RDMSharp { - public abstract class AbstractRDMDevice : IRDMDevice + public abstract class AbstractRDMDevice : AbstractRDMCache, IRDMDevice { private static readonly Random random = new Random(); private protected static readonly ILogger Logger = null; - private protected static RDMParameterWrapperCatalogueManager pmManager => RDMParameterWrapperCatalogueManager.GetInstance(); - private protected static DeviceInfoParameterWrapper deviceInfoParameterWrapper => (DeviceInfoParameterWrapper)pmManager.GetRDMParameterWrapperByID(ERDM_Parameter.DEVICE_INFO); - private protected static SensorValueParameterWrapper sensorValueParameterWrapper => (SensorValueParameterWrapper)pmManager.GetRDMParameterWrapperByID(ERDM_Parameter.SENSOR_VALUE); - private protected static SlotInfoParameterWrapper slotInfoParameterWrapper => (SlotInfoParameterWrapper)pmManager.GetRDMParameterWrapperByID(ERDM_Parameter.SLOT_INFO); - private protected static DefaultSlotValueParameterWrapper defaultSlotValueParameterWrapper => (DefaultSlotValueParameterWrapper)pmManager.GetRDMParameterWrapperByID(ERDM_Parameter.DEFAULT_SLOT_VALUE); - private protected static SlotDescriptionParameterWrapper slotDescriptionParameterWrapper => (SlotDescriptionParameterWrapper)pmManager.GetRDMParameterWrapperByID(ERDM_Parameter.SLOT_DESCRIPTION); - private protected static StatusMessageParameterWrapper statusMessageParameterWrapper => (StatusMessageParameterWrapper)pmManager.GetRDMParameterWrapperByID(ERDM_Parameter.STATUS_MESSAGES); - - private readonly AsyncRDMRequestHelper asyncRDMRequestHelper; public event PropertyChangedEventHandler PropertyChanged; - public UID UID { get; private set; } - public DateTime LastSeen { get; private set; } - public bool Present { get; internal set; } - public bool DiscoveryMuted { get; private set; } + public readonly UID uid; + public readonly SubDevice subdevice; + public UID UID => uid; + public SubDevice Subdevice => subdevice; + private DateTime lastSeen; + public DateTime LastSeen + { + get + { + return lastSeen; + } + private set + { + if (lastSeen == value) + return; + lastSeen = value; + OnPropertyChanged(nameof(LastSeen)); + } + } + + private bool present; + public bool Present + { + get + { + return present; + } + internal set + { + if (present == value) + return; + present = value; + OnPropertyChanged(nameof(Present)); + } + } + + private bool discoveryMuted; + public bool DiscoveryMuted + { + get + { + return discoveryMuted; + } + private set + { + if (discoveryMuted == value) + return; + discoveryMuted = value; + OnPropertyChanged(nameof(DiscoveryMuted)); + } + } + + private List subDevices; + public IReadOnlyCollection SubDevices { get { return subDevices.AsReadOnly(); } } public virtual RDMDeviceInfo DeviceInfo { get; private protected set; } private RDMDeviceModel deviceModel; - public RDMDeviceModel DeviceModel => deviceModel; + public RDMDeviceModel DeviceModel + { + get { return deviceModel; } + private set + { + if (deviceModel == value) + return; + deviceModel = value; + OnPropertyChanged(nameof(DeviceModel)); + } + } - private readonly ConcurrentDictionary parameterValues = new ConcurrentDictionary(); - public IReadOnlyDictionary ParameterValues => parameterValues.AsReadOnly(); + public sealed override IReadOnlyDictionary ParameterValues + { + get + { + if (DeviceModel == null) + return parameterValues.AsReadOnly(); + + return DeviceModel.ParameterValues.Where(x => !parameterValues.ContainsKey(x.Key)).Concat(parameterValues).ToDictionary(k => k.Key, v => v.Value).AsReadOnly(); + } + } private readonly HashSet pendingParametersUpdateRequest = new HashSet(); private readonly ConcurrentDictionary sensors = new ConcurrentDictionary(); @@ -47,22 +107,111 @@ public abstract class AbstractRDMDevice : IRDMDevice public IReadOnlyDictionary Slots => slots.AsReadOnly(); private readonly HashSet pendingSlotDescriptionsUpdateRequest = new HashSet(); - public bool IsDisposing { get; private set; } - - public bool IsDisposed { get; private set; } + public new bool IsDisposing { get; private set; } + public new bool IsDisposed { get; private set; } public virtual bool IsGenerated { get; private protected set; } - public bool AllDataPulled { get; private set; } + private bool allDataPulled; + public bool AllDataPulled + { + get + { + return allDataPulled; + } + private set + { + if (allDataPulled == value) + return; + allDataPulled = value; + OnPropertyChanged(nameof(AllDataPulled)); + } + } + + public AbstractRDMDevice(UID uid): this(uid, SubDevice.Root) + { + } - public AbstractRDMDevice(UID uid) + public AbstractRDMDevice(UID uid, SubDevice subDevice) { + this.uid = uid; + this.subdevice = subDevice; + subDevices = new List(); + asyncRDMRequestHelper = new AsyncRDMRequestHelper(sendRDMRequestMessage); - UID = uid; + initialize(); } + private async void initialize() { if (!IsGenerated) - await sendRDMRequestMessage(deviceInfoParameterWrapper.BuildGetRequestMessage()); + await requestDeviceInfo(); + } + + #region Requests + + private async Task requestDeviceInfo() + { + PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.GET_COMMAND, UID, Subdevice, new ParameterBag(ERDM_Parameter.DEVICE_INFO)); + await runPeerToPeerProcess(ptpProcess); + if (ptpProcess.ResponsePayloadObject.ParsedObject is RDMDeviceInfo deviceInfo) + { + DeviceInfo = deviceInfo; + updateParameterValuesDependeciePropertyBag(ERDM_Parameter.DEVICE_INFO, ptpProcess.ResponsePayloadObject); + updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ERDM_Parameter.DEVICE_INFO), ptpProcess.ResponsePayloadObject); + await getDeviceModelAndCollectAllParameters(); + } + } + private async Task requestSensorValue(byte sensorId) + { + DataTreeBranch dataTreeBranch = new DataTreeBranch(new DataTree("sensor",0, sensorId)); + PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.GET_COMMAND, UID, Subdevice, new ParameterBag(ERDM_Parameter.SENSOR_VALUE), dataTreeBranch); + await runPeerToPeerProcess(ptpProcess); + if (ptpProcess.ResponsePayloadObject.ParsedObject is RDMSensorValue sensorValue) + { + //DeviceInfo = deviceInfo; + //parameterValues.AddOrUpdate(ERDM_Parameter.DEVICE_INFO, deviceInfo, (o, p) => deviceInfo); + //await getDeviceModelAndCollectAllParameters(); + } + } + private async Task requestParameters() + { + var parameters = this.DeviceModel?.SupportedNonBlueprintParameters; + if (parameters == null) + return; + + foreach (ERDM_Parameter parameter in parameters) + { + switch(parameter) + { + case ERDM_Parameter.DEVICE_INFO: + continue; + } + ParameterBag parameterBag = new ParameterBag(parameter, this.DeviceModel.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); + var define = MetadataFactory.GetDefine(parameterBag); + if (define.GetRequest.HasValue) + { + if (define.GetRequest.Value.GetIsEmpty()) + await requestParameterWithEmptyPayload(parameterBag, define, UID, Subdevice); + else + await requestParameterWithPayload(parameterBag, define, UID, Subdevice); + } + } + } + + #endregion + + private async Task getDeviceModelAndCollectAllParameters() + { + if (deviceModel != null) + return; + deviceModel = RDMDeviceModel.getDeviceModel(UID, Subdevice, DeviceInfo, new Func(SendRDMMessage)); + if (!deviceModel.IsInitialized) + { + deviceModel.Initialized += DeviceModel_Initialized; + await deviceModel.Initialize(); + } + else + await collectAllParameters(); } private protected void SetGeneratedParameterValue(ERDM_Parameter parameter, object value) @@ -100,19 +249,9 @@ public async Task SetParameter(ERDM_Parameter parameter, object value = nu { try { - var pm = pmManager.GetRDMParameterWrapperByID(parameter); RDMMessage request = null; - switch (pm) - { - case IRDMSetParameterWrapperWithEmptySetRequest emptySetRequest: - request = emptySetRequest.BuildSetRequestMessage(); - break; - case IRDMSetParameterWrapperRequest setRequest: - request = setRequest.BuildSetRequestMessage(value); - value = setRequest.SetRequestParameterDataToObject(request.ParameterData); - break; - } + //ToDo SET Parameter if (request != null) { @@ -169,7 +308,7 @@ protected async Task ReceiveRDMMessage(RDMMessage rdmMessage) LastSeen = DateTime.UtcNow; - if (asyncRDMRequestHelper.ReceiveMethode(rdmMessage)) + if (asyncRDMRequestHelper.ReceiveMessage(rdmMessage)) return; if ((rdmMessage.NackReason?.Length ?? 0) != 0) @@ -179,11 +318,10 @@ protected async Task ReceiveRDMMessage(RDMMessage rdmMessage) if (deviceModel?.IsInitialized == false) return; - await processResponseMessage(rdmMessage); } private async Task requestParameter(RDMMessage rdmMessage) { - return await asyncRDMRequestHelper.RequestParameter(rdmMessage); + return await asyncRDMRequestHelper.RequestMessage(rdmMessage); } private async void DeviceModel_Initialized(object sender, EventArgs e) { @@ -192,16 +330,11 @@ private async void DeviceModel_Initialized(object sender, EventArgs e) } private async Task collectAllParameters() { - await UpdateParameterValues(); - await UpdateSensorValues(); - await UpdateSlotInfo(); - await UpdateDefaultSlotValue(); - await UpdateSlotDescriptions(); + await requestParameters(); AllDataPulled = true; } protected RDMMessage processRequestMessage(RDMMessage rdmMessage) { - var pm = pmManager.GetRDMParameterWrapperByID(rdmMessage.Parameter); RDMMessage response = null; try { @@ -247,243 +380,43 @@ protected RDMMessage processRequestMessage(RDMMessage rdmMessage) } if (rdmMessage.Command == ERDM_Command.GET_COMMAND) { - ConcurrentDictionary list = null; - object value = null; - object index = null; parameterValues.TryGetValue(rdmMessage.Parameter, out object responseValue); - switch (pm) + try { - case DeviceInfoParameterWrapper _deviceInfoParameterWrapper: - response = _deviceInfoParameterWrapper.BuildGetResponseMessage(DeviceInfo); - break; - - case SupportedParametersParameterWrapper _supportedParametersParameterWrapper: - List sp = new List(); - sp.Add(ERDM_Parameter.DEVICE_INFO); - sp.AddRange(parameterValues.Keys); - if (deviceModel != null) - sp.AddRange(deviceModel.SupportedParameters); - if (!sensors.IsEmpty) - { - sp.Add(ERDM_Parameter.SENSOR_DEFINITION); - sp.Add(ERDM_Parameter.SENSOR_VALUE); - if(sensors.Any(s=>s.Value.RecordedValueSupported)) - sp.Add(ERDM_Parameter.RECORD_SENSORS); - } - response = _supportedParametersParameterWrapper.BuildGetResponseMessage(sp.Distinct().ToArray()); - break; - case QueuedMessageParameterWrapper _queuedMessageParameterWrapper: - response = statusMessageParameterWrapper.BuildGetResponseMessage([]); - break; - case SlotInfoParameterWrapper slotInfoParameterWrapper: - list = null; - if (parameterValues.TryGetValue(rdmMessage.Parameter, out value)) - list = value as ConcurrentDictionary; - - if (list == null) - break; - - var slotInfos = list.Select(s => s.Value).OfType().ToArray(); - response = slotInfoParameterWrapper.BuildGetResponseMessage(slotInfos); - break; - case DefaultSlotValueParameterWrapper defaultSlotValueParameterWrapper: - list = null; - if (parameterValues.TryGetValue(rdmMessage.Parameter, out value)) - list = value as ConcurrentDictionary; - - if (list == null) - break; - - var defaultValues = list.Select(s => s.Value).OfType().ToArray(); - response = defaultSlotValueParameterWrapper.BuildGetResponseMessage(defaultValues); - break; - - case IRDMDescriptionParameterWrapper _descriptionParameterWrapper: - index = _descriptionParameterWrapper.GetRequestParameterDataToObject(rdmMessage.ParameterData); - if (index == null) - break; - - list = null; - if (parameterValues.TryGetValue(rdmMessage.Parameter, out value)) - list = value as ConcurrentDictionary; - - if (list == null && !IsGenerated) - parameterValues[rdmMessage.Parameter] = DeviceModel.ParameterValues[rdmMessage.Parameter]; - - if (list == null) - break; - - list.TryGetValue(index, out responseValue); - if (responseValue == null) - break; - response = _descriptionParameterWrapper.BuildGetResponseMessage(responseValue); - break; - - case DMX512StartingAddressParameterWrapper dmx512StartingAddressParameterWrapper - when responseValue is ushort _ushort: - response = dmx512StartingAddressParameterWrapper.BuildGetResponseMessage(_ushort); - break; - case SensorValueParameterWrapper sensorValueParameterWrapper: - if (sensors.TryGetValue((byte)rdmMessage.Value, out Sensor sensor)) - response = sensorValueParameterWrapper.BuildGetResponseMessage((RDMSensorValue)sensor); - break; - - case IRDMGetParameterWrapperResponse getParameterWrapperResponse: - response = getParameterWrapperResponse.BuildGetResponseMessage(responseValue); - break; + var parameterBag = new ParameterBag(rdmMessage.Parameter, UID.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); + var dataTreeBranch = DataTreeBranch.FromObject(responseValue, rdmMessage.Value, parameterBag, ERDM_Command.GET_COMMAND_RESPONSE); + if (!dataTreeBranch.IsUnset) + { + var data = MetadataFactory.GetResponseMessageData(parameterBag, dataTreeBranch); + if (data != null) + response = new RDMMessage + { + Parameter = rdmMessage.Parameter, + Command = ERDM_Command.GET_COMMAND_RESPONSE, + ParameterData = data, + }; + } + else + goto FAIL; + } + catch (Exception e) + { + goto FAIL; } } else if (rdmMessage.Command == ERDM_Command.SET_COMMAND) { bool success = false; //Handle set Requerst - switch (pm) - { - case IRDMSetParameterWrapperRequestContravariance setParameterWrapperRequestContravarianceBool - when setParameterWrapperRequestContravarianceBool.SetRequestParameterDataToObject(rdmMessage.ParameterData) is bool _bool: - success = updateParametrerValueCache(rdmMessage.Parameter, _bool); - break; - - case IRDMSetParameterWrapperRequestContravariance setParameterWrapperRequestContravarianceString - when setParameterWrapperRequestContravarianceString.SetRequestParameterDataToObject(rdmMessage.ParameterData) is string _string: - success = updateParametrerValueCache(rdmMessage.Parameter, _string); - break; - - case IRDMSetParameterWrapperRequestContravariance setParameterWrapperRequestContravarianceByte - when setParameterWrapperRequestContravarianceByte.SetRequestParameterDataToObject(rdmMessage.ParameterData) is byte _byte: - success = updateParametrerValueCache(rdmMessage.Parameter, _byte); - break; - - case IRDMSetParameterWrapperRequestContravariance setParameterWrapperRequestContravarianceSByte - when setParameterWrapperRequestContravarianceSByte.SetRequestParameterDataToObject(rdmMessage.ParameterData) is sbyte _sbyte: - success = updateParametrerValueCache(rdmMessage.Parameter, _sbyte); - break; - - case IRDMSetParameterWrapperRequestContravariance setParameterWrapperRequestContravarianceShort - when setParameterWrapperRequestContravarianceShort.SetRequestParameterDataToObject(rdmMessage.ParameterData) is short _short: - success = updateParametrerValueCache(rdmMessage.Parameter, _short); - break; - - case IRDMSetParameterWrapperRequestContravariance setParameterWrapperRequestContravarianceUShort - when setParameterWrapperRequestContravarianceUShort.SetRequestParameterDataToObject(rdmMessage.ParameterData) is ushort _ushort: - success = updateParametrerValueCache(rdmMessage.Parameter, _ushort); - break; - - case IRDMSetParameterWrapperRequestContravariance setParameterWrapperRequestContravarianceInt - when setParameterWrapperRequestContravarianceInt.SetRequestParameterDataToObject(rdmMessage.ParameterData) is int _int: - success = updateParametrerValueCache(rdmMessage.Parameter, _int); - break; - - case IRDMSetParameterWrapperRequestContravariance setParameterWrapperRequestContravarianceUInt - when setParameterWrapperRequestContravarianceUInt.SetRequestParameterDataToObject(rdmMessage.ParameterData) is uint _uint: - success = updateParametrerValueCache(rdmMessage.Parameter, _uint); - break; - - case IRDMSetParameterWrapperRequestContravariance setParameterWrapperRequestContravarianceLong - when setParameterWrapperRequestContravarianceLong.SetRequestParameterDataToObject(rdmMessage.ParameterData) is long _long: - success = updateParametrerValueCache(rdmMessage.Parameter, _long); - break; - - case IRDMSetParameterWrapperRequestContravariance setParameterWrapperRequestContravarianceULong - when setParameterWrapperRequestContravarianceULong.SetRequestParameterDataToObject(rdmMessage.ParameterData) is ulong _ulong: - success = updateParametrerValueCache(rdmMessage.Parameter, _ulong); - break; - - case IRDMSetParameterWrapperRequestContravariance setParameterWrapperRequestContravarianceDouble - when setParameterWrapperRequestContravarianceDouble.SetRequestParameterDataToObject(rdmMessage.ParameterData) is double _double: - success = updateParametrerValueCache(rdmMessage.Parameter, _double); - break; - - case IRDMSetParameterWrapperRequestContravariance setParameterWrapperRequestContravarianceFloat - when setParameterWrapperRequestContravarianceFloat.SetRequestParameterDataToObject(rdmMessage.ParameterData) is float _float: - success = updateParametrerValueCache(rdmMessage.Parameter, _float); - break; - } + + //ToDo SET Parameter + + //Do set Response if (!success) { response = new RDMMessage(ERDM_NackReason.FORMAT_ERROR) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; goto FAIL; } - //Do set Response - object val = null; - switch (pm) - { - case IRDMSetParameterWrapperWithEmptySetResponse setParameterWrapperResponseContravarianceEmpty: - response = setParameterWrapperResponseContravarianceEmpty.BuildSetResponseMessage(); - break; - - case IRDMSetParameterWrapperSetResponseContravariance setParameterWrapperResponseContravarianceBool: - parameterValues.TryGetValue(rdmMessage.Parameter, out val); - if (val is bool _bool) - response = setParameterWrapperResponseContravarianceBool.BuildSetResponseMessage(_bool); - break; - - case IRDMSetParameterWrapperSetResponseContravariance setParameterWrapperResponseContravarianceString: - parameterValues.TryGetValue(rdmMessage.Parameter, out val); - if (val is string _string) - response = setParameterWrapperResponseContravarianceString.BuildSetResponseMessage(_string); - break; - - case IRDMSetParameterWrapperSetResponseContravariance setParameterWrapperResponseContravarianceByte: - parameterValues.TryGetValue(rdmMessage.Parameter, out val); - if (val is byte _byte) - response = setParameterWrapperResponseContravarianceByte.BuildSetResponseMessage(_byte); - break; - - case IRDMSetParameterWrapperSetResponseContravariance setParameterWrapperResponseContravarianceSByte: - parameterValues.TryGetValue(rdmMessage.Parameter, out val); - if (val is sbyte _sbyte) - response = setParameterWrapperResponseContravarianceSByte.BuildSetResponseMessage(_sbyte); - break; - - case IRDMSetParameterWrapperSetResponseContravariance setParameterWrapperResponseContravarianceShort: - parameterValues.TryGetValue(rdmMessage.Parameter, out val); - if (val is short _short) - response = setParameterWrapperResponseContravarianceShort.BuildSetResponseMessage(_short); - break; - - case IRDMSetParameterWrapperSetResponseContravariance setParameterWrapperResponseContravarianceUShort: - parameterValues.TryGetValue(rdmMessage.Parameter, out val); - if (val is ushort _ushort) - response = setParameterWrapperResponseContravarianceUShort.BuildSetResponseMessage(_ushort); - break; - - case IRDMSetParameterWrapperSetResponseContravariance setParameterWrapperResponseContravarianceInt: - parameterValues.TryGetValue(rdmMessage.Parameter, out val); - if (val is int _int) - response = setParameterWrapperResponseContravarianceInt.BuildSetResponseMessage(_int); - break; - - case IRDMSetParameterWrapperSetResponseContravariance setParameterWrapperResponseContravarianceUInt: - parameterValues.TryGetValue(rdmMessage.Parameter, out val); - if (val is uint _uint) - response = setParameterWrapperResponseContravarianceUInt.BuildSetResponseMessage(_uint); - break; - - case IRDMSetParameterWrapperSetResponseContravariance setParameterWrapperResponseContravarianceLong: - parameterValues.TryGetValue(rdmMessage.Parameter, out val); - if (val is long _long) - response = setParameterWrapperResponseContravarianceLong.BuildSetResponseMessage(_long); - break; - - case IRDMSetParameterWrapperSetResponseContravariance setParameterWrapperResponseContravarianceULong: - parameterValues.TryGetValue(rdmMessage.Parameter, out val); - if (val is ulong _ulong) - response = setParameterWrapperResponseContravarianceULong.BuildSetResponseMessage(_ulong); - break; - - case IRDMSetParameterWrapperSetResponseContravariance setParameterWrapperResponseContravarianceDouble: - parameterValues.TryGetValue(rdmMessage.Parameter, out val); - if (val is double _double) - response = setParameterWrapperResponseContravarianceDouble.BuildSetResponseMessage(_double); - break; - - case IRDMSetParameterWrapperSetResponseContravariance setParameterWrapperResponseContravarianceFloat: - parameterValues.TryGetValue(rdmMessage.Parameter, out val); - if (val is float _float) - response = setParameterWrapperResponseContravarianceFloat.BuildSetResponseMessage(_float); - break; - } } } catch (Exception e) @@ -503,483 +436,305 @@ when setParameterWrapperRequestContravarianceFloat.SetRequestParameterDataToObje return response; } - private async Task processResponseMessage(RequestResult result) - { - if (IsGenerated) - return; - - if (result.Success) - await processResponseMessage(result.Response); - else if (result.Cancel) - return; - else - { - await Task.Delay(TimeSpan.FromTicks(random.Next(4500, 5500))); - await processResponseMessage(await requestParameter(result.Request)); - } - } - private async Task processResponseMessage(RDMMessage rdmMessage) - { - if (IsGenerated) - return; - - if (rdmMessage.Parameter != ERDM_Parameter.DEVICE_INFO && (this.DeviceModel?.SupportedBlueprintParameters.Contains(rdmMessage.Parameter) ?? false)) - return; - - if (rdmMessage.NackReason != null) - if (rdmMessage.NackReason.Length != 0) - return; - - var pm = pmManager.GetRDMParameterWrapperByID(rdmMessage.Parameter); - object value = null; - try - { - value = rdmMessage.Value; - } - catch (Exception ex) - { - Logger?.LogError(ex); - } - if (value == null) - return; - ConcurrentDictionary list = null; - switch (pm) - { - case DeviceInfoParameterWrapper _deviceInfoParameterWrapper: - if (rdmMessage.Value is not RDMDeviceInfo deviceInfo) - break; - - DeviceInfo = deviceInfo; - - if (deviceModel != null) - break; - - deviceModel = RDMDeviceModel.getDeviceModel(UID, deviceInfo, new Func(SendRDMMessage)); - if (!deviceModel.IsInitialized) - { - deviceModel.Initialized += DeviceModel_Initialized; - await deviceModel.Initialize(); - } - else - await collectAllParameters(); - - break; - - case SlotDescriptionParameterWrapper _slotDescriptionParameterWrapper: - if (value is not RDMSlotDescription description) - { - if (value != null) - Logger?.LogError($"The response does not contain the expected data {typeof(RDMSlotDescription)}!{Environment.NewLine}{rdmMessage}"); - else - Logger?.LogTrace($"No response received"); - return; - } - - - if (parameterValues.TryGetValue(rdmMessage.Parameter, out value)) - list = value as ConcurrentDictionary; - if (list == null) - parameterValues[rdmMessage.Parameter] = list = new ConcurrentDictionary(); - list.AddOrUpdate(description.SlotId, description, (e, f) => description); - Slot slot; - if (!slots.TryGetValue(description.SlotId, out slot)) - { - slot = new Slot(description.SlotId); - slots.TryAdd(slot.SlotId, slot); - } - slot.UpdateSlotDescription(description); - this.OnPropertyChanged(nameof(this.Slots)); - break; - - case SlotInfoParameterWrapper _slotInfoParameterWrapper: - if (value is not RDMSlotInfo[] slotInfos) - { - if (rdmMessage.NackReason.Contains(ERDM_NackReason.ACTION_NOT_SUPPORTED)) - this.slots = null; //Set to null, to Deactivate this UpdateSlotInfo - - Logger?.LogError($"The response does not contain the expected data {typeof(RDMSlotInfo[])}!{Environment.NewLine}{rdmMessage}"); - return; - } - - if (parameterValues.TryGetValue(rdmMessage.Parameter, out value)) - list = value as ConcurrentDictionary; - if (list == null) - parameterValues[rdmMessage.Parameter] = list = new ConcurrentDictionary(); - - foreach (RDMSlotInfo info in slotInfos) - { - list.AddOrUpdate(info.SlotOffset, info, (e, f) => info); - - if (!slots.TryGetValue(info.SlotOffset, out Slot slot1)) - { - slot1 = new Slot(info.SlotOffset); - slots.TryAdd(info.SlotOffset, slot1); - } - slot1.UpdateSlotInfo(info); - } - this.OnPropertyChanged(nameof(this.Slots)); - break; - - case DefaultSlotValueParameterWrapper _defaultSlotValueParameterWrapper: - if (value is not RDMDefaultSlotValue[] defaultSlotValues) - { - Logger?.LogError($"The response does not contain the expected data {typeof(RDMDefaultSlotValue[])}!{Environment.NewLine}{rdmMessage}"); - return; - } - - - if (parameterValues.TryGetValue(rdmMessage.Parameter, out value)) - list = value as ConcurrentDictionary; - if (list == null) - parameterValues[rdmMessage.Parameter] = list = new ConcurrentDictionary(); - - foreach (RDMDefaultSlotValue info in defaultSlotValues) - { - list.AddOrUpdate(info.SlotOffset, info, (e, f) => info); - if (!slots.TryGetValue(info.SlotOffset, out Slot slot1)) - { - slot1 = new Slot(info.SlotOffset); - slots.TryAdd(info.SlotOffset, slot1); - } - slot1.UpdateSlotDefaultValue(info); - } - this.OnPropertyChanged(nameof(this.Slots)); - break; - case SensorValueParameterWrapper _sensorValueParameterWrapper: - if (value is not RDMSensorValue sensorValue) - { - if (value != null) - Logger?.LogError($"The response does not contain the expected data {typeof(RDMSensorDefinition)}!{Environment.NewLine}{rdmMessage}"); - else - Logger?.LogError($"No response received"); - return; - } - Sensor sensorV = sensors.GetOrAdd(sensorValue.SensorId, (a) => new Sensor(a)); - sensorV.UpdateValue(sensorValue); - this.OnPropertyChanged(nameof(this.Sensors)); - break; - - case IRDMGetParameterWrapperWithEmptyGetRequest @emptyGetRequest: - updateParametrerValueCache(rdmMessage.Parameter, value); - break; - - case IRDMGetParameterWrapperRequest @emptyGetRequest: - updateParametrerValueCache(rdmMessage.Parameter, value); - break; - case IRDMGetParameterWrapperRequest @emptyGetRequest: - updateParametrerValueCache(rdmMessage.Parameter, value); - break; - case IRDMGetParameterWrapperRequest @emptyGetRequest: - updateParametrerValueCache(rdmMessage.Parameter, value); - break; - - default: - break; - - } - } - protected virtual void OnPropertyChanged(string property) { this.PropertyChanged.InvokeFailSafe(this, new PropertyChangedEventArgs(property)); } - public async Task UpdateParameterValues() - { - if (IsGenerated) - return; - - if (this.DeviceModel == null) - return; - - try - { - foreach (ERDM_Parameter parameter in this.DeviceModel.SupportedNonBlueprintParameters) - await this.UpdateParameterValue(parameter); - } - catch (Exception e) - { - Logger?.LogError($"Not able to get UpdateParameterValues for UID: {this.UID}", e); - } - } - public async Task UpdateParameterValue(ERDM_Parameter parameterId) - { - if (IsGenerated) - return; - - if (this.DeviceModel == null) - return; - if (this.pendingParametersUpdateRequest.Contains(parameterId)) - return; - - switch (parameterId) - { - case ERDM_Parameter.SENSOR_DEFINITION: - case ERDM_Parameter.SENSOR_VALUE: - case ERDM_Parameter.SLOT_INFO: - case ERDM_Parameter.SLOT_DESCRIPTION: - case ERDM_Parameter.DEFAULT_SLOT_VALUE: - case ERDM_Parameter.QUEUED_MESSAGE: - return; - } - - var pm = pmManager.GetRDMParameterWrapperByID(parameterId); - if (pm == null && Enum.IsDefined(typeof(ERDM_Parameter), parameterId)) - return; - - pm ??= deviceModel.GetRDMParameterWrapperByID((ushort)parameterId); - if (pm == null) - { - Logger?.LogDebug("Not Implemented Parameter"); - return; - } - - if (!pm.CommandClass.HasFlag(ERDM_CommandClass.GET)) - return; - - if (pm is IRDMBlueprintParameterWrapper) - return; - - this.pendingParametersUpdateRequest.Add(parameterId); - try - { - List tasks = new List(); - object val = null; - switch (pm) - { - case IRDMGetParameterWrapperWithEmptyGetRequest @emptyGetRequest: - tasks.Add(processResponseMessage(await requestParameter(@emptyGetRequest.BuildGetRequestMessage()))); - break; - case IRDMGetParameterWrapperRequestRanged @byteGetRequest: - foreach (ERDM_Parameter para in @byteGetRequest.DescriptiveParameters) - { - this.DeviceModel.ParameterValues.TryGetValue(para, out val); - if (val != null) - break; - } - foreach (var r in @byteGetRequest.GetRequestRange(val).ToEnumerator()) - tasks.Add(processResponseMessage(await requestParameter(@byteGetRequest.BuildGetRequestMessage(r)))); - - break; - case IRDMGetParameterWrapperRequestRanged @ushortGetRequest: - foreach (ERDM_Parameter para in @ushortGetRequest.DescriptiveParameters) - { - this.DeviceModel.ParameterValues.TryGetValue(para, out val); - if (val != null) - break; - } - foreach (var r in @ushortGetRequest.GetRequestRange(val).ToEnumerator()) - tasks.Add(processResponseMessage(await requestParameter(@ushortGetRequest.BuildGetRequestMessage(r)))); - - break; - case IRDMGetParameterWrapperRequestRanged @uintGetRequest: - foreach (ERDM_Parameter para in @uintGetRequest.DescriptiveParameters) - { - this.DeviceModel.ParameterValues.TryGetValue(para, out val); - if (val != null) - break; - } - foreach (var r in @uintGetRequest.GetRequestRange(val).ToEnumerator()) - tasks.Add(processResponseMessage(await requestParameter(@uintGetRequest.BuildGetRequestMessage(r)))); - - break; - - case StatusMessageParameterWrapper statusMessageParameter: - tasks.Add(processResponseMessage(await requestParameter(statusMessageParameter.BuildGetRequestMessage(ERDM_Status.ADVISORY)))); - break; - default: - Logger?.LogDebug($"No Wrapper for Parameter: {parameterId} for UID: {this.UID}"); - break; - } - await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(TimeSpan.FromSeconds(10))); - } - catch (Exception e) - { - Logger?.LogError($"Not able to update ParameterValue of Parameter: {parameterId} for UID: {this.UID}", e); - } - this.pendingParametersUpdateRequest.Remove(parameterId); - } - public async Task UpdateSensorValues() - { - if (IsGenerated) - return; - - if (this.DeviceInfo == null) - return; - - if (this.DeviceModel?.SupportedParameters?.Contains(ERDM_Parameter.SENSOR_DEFINITION) != true) - return; - - if (this.DeviceModel == null) - return; - - if (this.DeviceInfo.SensorCount == 0) - return; - - try - { - List tasks = new List(); - foreach (var sd in this.DeviceModel.GetSensorDefinitions()) - { - sensors.GetOrAdd(sd.SensorId, (a) => - { - var s = new Sensor(a); - s.UpdateDescription(sd); - return s; - }); - - tasks.Add(this.UpdateSensorValue(sd.SensorId)); - } - - await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(TimeSpan.FromSeconds(10))); - } - catch (Exception e) - { - Logger?.LogError($"Not able to update SensorValues for UID: {this.UID}", e); - } - } - public async Task UpdateSensorValue(byte sensorId) - { - if (IsGenerated) - return; - - if (this.DeviceInfo == null) - return; - if (this.DeviceModel?.SupportedParameters?.Contains(ERDM_Parameter.SENSOR_VALUE) != true) - return; - if (this.pendingSensorValuesUpdateRequest.Contains(sensorId)) - return; - - if (this.DeviceInfo.SensorCount == 0) - return; - - try - { - this.pendingSensorValuesUpdateRequest.Add(sensorId); - await processResponseMessage(await requestParameter(sensorValueParameterWrapper.BuildGetRequestMessage(sensorId))); - } - catch (Exception e) - { - Logger?.LogError($"Not able to update SensorValue of Sensor: {sensorId} for UID: {this.UID}", e); - } - this.pendingSensorValuesUpdateRequest.Remove(sensorId); - } - public async Task UpdateSlotInfo() - { - if (IsGenerated) - return; - - if (this.DeviceInfo == null || this.slots == null) - return; - - if (this.DeviceModel?.SupportedParameters?.Contains(ERDM_Parameter.SLOT_INFO) != true) - return; - - try - { - RequestResult? result = null; - do - { - result = await requestParameter(slotInfoParameterWrapper.BuildGetRequestMessage()); - if (result.Value.Success) - await processResponseMessage(result.Value.Response); - else if (result.Value.Cancel) - return; - else - await Task.Delay(TimeSpan.FromTicks(random.Next(2500, 3500))); - } - while (result?.Response?.ResponseType == ERDM_ResponseType.ACK_OVERFLOW || result?.Response == null); - } - catch (Exception e) - { - Logger?.LogError($"Not able to update SlotInfo for UID: {this.UID}", e); - } - } - public async Task UpdateDefaultSlotValue() - { - if (IsGenerated) - return; - - if (this.DeviceInfo == null || this.slots == null) - return; - - if (this.DeviceModel?.SupportedParameters?.Contains(ERDM_Parameter.DEFAULT_SLOT_VALUE) != true) - return; - - try - { - RequestResult? result = null; - do - { - result = await requestParameter(defaultSlotValueParameterWrapper.BuildGetRequestMessage()); - if (result.Value.Success) - await processResponseMessage(result.Value.Response); - else if (result.Value.Cancel) - return; - else - await Task.Delay(TimeSpan.FromTicks(random.Next(2500, 3500))); - } - while (result?.Response?.ResponseType == ERDM_ResponseType.ACK_OVERFLOW || result?.Response == null); - } - catch (Exception e) - { - Logger?.LogError($"Not able to update DefaultSlotValue for UID: {this.UID}", e); - } - } - public async Task UpdateSlotDescriptions() - { - if (IsGenerated) - return; - - if (this.DeviceInfo == null) - return; - - if (this.DeviceModel?.SupportedParameters?.Contains(ERDM_Parameter.SLOT_DESCRIPTION) != true) - return; - - if (this.Slots.Count == 0) - return; - - try - { - List tasks = new List(); - foreach (var slot in this.slots) - tasks.Add(this.UpdateSlotDescription(slot.Key)); - - await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(TimeSpan.FromSeconds(10))); - } - catch (Exception e) - { - Logger?.LogError($"Not able to update SlotDescriptions for UID: {this.UID}", e); - } - } - public async Task UpdateSlotDescription(ushort slotId) - { - if (IsGenerated) - return; - - if (this.DeviceInfo == null) - return; - if (this.DeviceModel?.SupportedParameters?.Contains(ERDM_Parameter.SLOT_DESCRIPTION) != true) - return; - - if (this.pendingSlotDescriptionsUpdateRequest.Contains(slotId)) - return; - - if (this.Slots.Count == 0) - return; - - try - { - this.pendingSlotDescriptionsUpdateRequest.Add(slotId); - await processResponseMessage(await requestParameter(slotDescriptionParameterWrapper.BuildGetRequestMessage(slotId))); - } - catch (Exception e) - { - Logger?.LogError($"Not able to update SlotDescription of Slot: {slotId} for UID: {this.UID}", e); - } - this.pendingSlotDescriptionsUpdateRequest.Remove(slotId); - } + //public async Task UpdateParameterValues() + //{ + // if (IsGenerated) + // return; + + // if (this.DeviceModel == null) + // return; + + // try + // { + // foreach (ERDM_Parameter parameter in this.DeviceModel.SupportedNonBlueprintParameters) + // await this.UpdateParameterValue(parameter); + // } + // catch (Exception e) + // { + // Logger?.LogError($"Not able to get UpdateParameterValues for UID: {this.UID}", e); + // } + //} + //public async Task UpdateParameterValue(ERDM_Parameter parameterId) + //{ + // if (IsGenerated) + // return; + + // if (this.DeviceModel == null) + // return; + // if (this.pendingParametersUpdateRequest.Contains(parameterId)) + // return; + + // switch (parameterId) + // { + // case ERDM_Parameter.SENSOR_DEFINITION: + // case ERDM_Parameter.SENSOR_VALUE: + // case ERDM_Parameter.SLOT_INFO: + // case ERDM_Parameter.SLOT_DESCRIPTION: + // case ERDM_Parameter.DEFAULT_SLOT_VALUE: + // case ERDM_Parameter.QUEUED_MESSAGE: + // return; + // } + + // var pm = pmManager.GetRDMParameterWrapperByID(parameterId); + // if (pm == null && Enum.IsDefined(typeof(ERDM_Parameter), parameterId)) + // return; + + + // if (!pm.CommandClass.HasFlag(ERDM_CommandClass.GET)) + // return; + + // if (pm is IRDMBlueprintParameterWrapper) + // return; + + // this.pendingParametersUpdateRequest.Add(parameterId); + // try + // { + // List tasks = new List(); + // object val = null; + // switch (pm) + // { + // case IRDMGetParameterWrapperWithEmptyGetRequest @emptyGetRequest: + // tasks.Add(processResponseMessage(await requestParameter(@emptyGetRequest.BuildGetRequestMessage()))); + // break; + // case IRDMGetParameterWrapperRequestRanged @byteGetRequest: + // foreach (ERDM_Parameter para in @byteGetRequest.DescriptiveParameters) + // { + // this.DeviceModel.ParameterValues.TryGetValue(para, out val); + // if (val != null) + // break; + // } + // foreach (var r in @byteGetRequest.GetRequestRange(val).ToEnumerator()) + // tasks.Add(processResponseMessage(await requestParameter(@byteGetRequest.BuildGetRequestMessage(r)))); + + // break; + // case IRDMGetParameterWrapperRequestRanged @ushortGetRequest: + // foreach (ERDM_Parameter para in @ushortGetRequest.DescriptiveParameters) + // { + // this.DeviceModel.ParameterValues.TryGetValue(para, out val); + // if (val != null) + // break; + // } + // foreach (var r in @ushortGetRequest.GetRequestRange(val).ToEnumerator()) + // tasks.Add(processResponseMessage(await requestParameter(@ushortGetRequest.BuildGetRequestMessage(r)))); + + // break; + // case IRDMGetParameterWrapperRequestRanged @uintGetRequest: + // foreach (ERDM_Parameter para in @uintGetRequest.DescriptiveParameters) + // { + // this.DeviceModel.ParameterValues.TryGetValue(para, out val); + // if (val != null) + // break; + // } + // foreach (var r in @uintGetRequest.GetRequestRange(val).ToEnumerator()) + // tasks.Add(processResponseMessage(await requestParameter(@uintGetRequest.BuildGetRequestMessage(r)))); + + // break; + + // case StatusMessageParameterWrapper statusMessageParameter: + // tasks.Add(processResponseMessage(await requestParameter(statusMessageParameter.BuildGetRequestMessage(ERDM_Status.ADVISORY)))); + // break; + // default: + // Logger?.LogDebug($"No Wrapper for Parameter: {parameterId} for UID: {this.UID}"); + // break; + // } + // await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(TimeSpan.FromSeconds(10))); + // } + // catch (Exception e) + // { + // Logger?.LogError($"Not able to update ParameterValue of Parameter: {parameterId} for UID: {this.UID}", e); + // } + // this.pendingParametersUpdateRequest.Remove(parameterId); + //} + //public async Task UpdateSensorValues() + //{ + // if (IsGenerated) + // return; + + // if (this.DeviceInfo == null) + // return; + + // if (this.DeviceModel?.SupportedParameters?.Contains(ERDM_Parameter.SENSOR_DEFINITION) != true) + // return; + + // if (this.DeviceModel == null) + // return; + + // if (this.DeviceInfo.SensorCount == 0) + // return; + + // try + // { + // var sensorDefenitions = this.DeviceModel.GetSensorDefinitions(); + // if (sensorDefenitions == null) + // return; + + // List tasks = new List(); + // foreach (var sd in sensorDefenitions) + // { + // sensors.GetOrAdd(sd.SensorId, (a) => + // { + // var s = new Sensor(a); + // s.UpdateDescription(sd); + // return s; + // }); + + // tasks.Add(this.UpdateSensorValue(sd.SensorId)); + // } + + // await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(TimeSpan.FromSeconds(10))); + // } + // catch (Exception e) + // { + // Logger?.LogError($"Not able to update SensorValues for UID: {this.UID}", e); + // } + //} + //public async Task UpdateSensorValue(byte sensorId) + //{ + // if (IsGenerated) + // return; + + // if (this.DeviceInfo == null) + // return; + // if (this.DeviceModel?.SupportedParameters?.Contains(ERDM_Parameter.SENSOR_VALUE) != true) + // return; + // if (this.pendingSensorValuesUpdateRequest.Contains(sensorId)) + // return; + + // if (this.DeviceInfo.SensorCount == 0) + // return; + + // try + // { + // this.pendingSensorValuesUpdateRequest.Add(sensorId); + // await processResponseMessage(await requestParameter(sensorValueParameterWrapper.BuildGetRequestMessage(sensorId))); + // } + // catch (Exception e) + // { + // Logger?.LogError($"Not able to update SensorValue of Sensor: {sensorId} for UID: {this.UID}", e); + // } + // this.pendingSensorValuesUpdateRequest.Remove(sensorId); + //} + //public async Task UpdateSlotInfo() + //{ + // if (IsGenerated) + // return; + + // if (this.DeviceInfo == null || this.slots == null) + // return; + + // if (this.DeviceModel?.SupportedParameters?.Contains(ERDM_Parameter.SLOT_INFO) != true) + // return; + + // try + // { + // RequestResult? result = null; + // do + // { + // result = await requestParameter(slotInfoParameterWrapper.BuildGetRequestMessage()); + // if (result.Value.Success) + // await processResponseMessage(result.Value.Response); + // else if (result.Value.Cancel) + // return; + // else + // await Task.Delay(TimeSpan.FromTicks(random.Next(2500, 3500))); + // } + // while (result?.Response?.ResponseType == ERDM_ResponseType.ACK_OVERFLOW || result?.Response == null); + // } + // catch (Exception e) + // { + // Logger?.LogError($"Not able to update SlotInfo for UID: {this.UID}", e); + // } + //} + //public async Task UpdateDefaultSlotValue() + //{ + // if (IsGenerated) + // return; + + // if (this.DeviceInfo == null || this.slots == null) + // return; + + // if (this.DeviceModel?.SupportedParameters?.Contains(ERDM_Parameter.DEFAULT_SLOT_VALUE) != true) + // return; + + // try + // { + // RequestResult? result = null; + // do + // { + // result = await requestParameter(defaultSlotValueParameterWrapper.BuildGetRequestMessage()); + // if (result.Value.Success) + // await processResponseMessage(result.Value.Response); + // else if (result.Value.Cancel) + // return; + // else + // await Task.Delay(TimeSpan.FromTicks(random.Next(2500, 3500))); + // } + // while (result?.Response?.ResponseType == ERDM_ResponseType.ACK_OVERFLOW || result?.Response == null); + // } + // catch (Exception e) + // { + // Logger?.LogError($"Not able to update DefaultSlotValue for UID: {this.UID}", e); + // } + //} + //public async Task UpdateSlotDescriptions() + //{ + // if (IsGenerated) + // return; + + // if (this.DeviceInfo == null) + // return; + + // if (this.DeviceModel?.SupportedParameters?.Contains(ERDM_Parameter.SLOT_DESCRIPTION) != true) + // return; + + // if (this.Slots.Count == 0) + // return; + + // try + // { + // List tasks = new List(); + // foreach (var slot in this.slots) + // tasks.Add(this.UpdateSlotDescription(slot.Key)); + + // await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(TimeSpan.FromSeconds(10))); + // } + // catch (Exception e) + // { + // Logger?.LogError($"Not able to update SlotDescriptions for UID: {this.UID}", e); + // } + //} + //public async Task UpdateSlotDescription(ushort slotId) + //{ + // if (IsGenerated) + // return; + + // if (this.DeviceInfo == null) + // return; + // if (this.DeviceModel?.SupportedParameters?.Contains(ERDM_Parameter.SLOT_DESCRIPTION) != true) + // return; + + // if (this.pendingSlotDescriptionsUpdateRequest.Contains(slotId)) + // return; + + // if (this.Slots.Count == 0) + // return; + + // try + // { + // this.pendingSlotDescriptionsUpdateRequest.Add(slotId); + // await processResponseMessage(await requestParameter(slotDescriptionParameterWrapper.BuildGetRequestMessage(slotId))); + // } + // catch (Exception e) + // { + // Logger?.LogError($"Not able to update SlotDescription of Slot: {slotId} for UID: {this.UID}", e); + // } + // this.pendingSlotDescriptionsUpdateRequest.Remove(slotId); + //} private bool updateParametrerValueCache(ERDM_Parameter parameter, object value) { @@ -1002,7 +757,7 @@ public IReadOnlyDictionary GetAllParameterValues() return this.ParameterValues; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1816:Dispose-Methoden müssen SuppressFinalize aufrufen", Justification = "")] - public void Dispose() + public new void Dispose() { if (IsDisposing || IsDisposed) return; diff --git a/RDMSharp/RDM/Device/ParameterDataCacheBag.cs b/RDMSharp/RDM/Device/ParameterDataCacheBag.cs new file mode 100644 index 0000000..75d198e --- /dev/null +++ b/RDMSharp/RDM/Device/ParameterDataCacheBag.cs @@ -0,0 +1,26 @@ +namespace RDMSharp +{ + public readonly struct ParameterDataCacheBag + { + public readonly ERDM_Parameter Parameter; + public readonly object Index; + + public ParameterDataCacheBag(ERDM_Parameter parameter, object index) + { + Parameter = parameter; + Index = index; + } + public ParameterDataCacheBag(ERDM_Parameter parameter) + { + Parameter = parameter; + } + + public override string ToString() + { + if (Index == null) + return $"{Parameter}"; + else + return $"{Parameter}: {Index}"; + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/RDMDeviceModel.cs b/RDMSharp/RDM/Device/RDMDeviceModel.cs index 3a73af9..514abd1 100644 --- a/RDMSharp/RDM/Device/RDMDeviceModel.cs +++ b/RDMSharp/RDM/Device/RDMDeviceModel.cs @@ -1,25 +1,28 @@ -using RDMSharp.ParameterWrapper; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON.OneOfTypes; +using RDMSharp.ParameterWrapper; using RDMSharp.ParameterWrapper.Generic; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Reflection; using System.Threading.Tasks; namespace RDMSharp { - public sealed class RDMDeviceModel : IRDMDeviceModel + public sealed class RDMDeviceModel : AbstractRDMCache, IRDMDeviceModel { private static ConcurrentDictionary knownDeviceModels; public static IReadOnlyCollection KnownDeviceModels => knownDeviceModels.Values.ToList(); - internal static RDMDeviceModel getDeviceModel(UID uid, RDMDeviceInfo deviceInfo, Func sendRdmFunktion) + internal static RDMDeviceModel getDeviceModel(UID uid, SubDevice subDevice, RDMDeviceInfo deviceInfo, Func sendRdmFunktion) { knownDeviceModels ??= new ConcurrentDictionary(); var kdm = knownDeviceModels.Values.FirstOrDefault(dm => dm.IsModelOf(uid, deviceInfo)); if (kdm == null) { - kdm = new RDMDeviceModel(uid, deviceInfo, sendRdmFunktion); + kdm = new RDMDeviceModel(uid, subDevice, deviceInfo, sendRdmFunktion); knownDeviceModels.TryAdd(kdm.GetHashCode(), kdm); } @@ -27,30 +30,45 @@ internal static RDMDeviceModel getDeviceModel(UID uid, RDMDeviceInfo deviceInfo, } - private static readonly Random random = new Random(); - private static RDMParameterWrapperCatalogueManager pmManager => RDMParameterWrapperCatalogueManager.GetInstance(); - private static DeviceInfoParameterWrapper deviceInfoParameterWrapper => (DeviceInfoParameterWrapper)pmManager.GetRDMParameterWrapperByID(ERDM_Parameter.DEVICE_INFO); - private static SupportedParametersParameterWrapper supportedParametersParameterWrapper => (SupportedParametersParameterWrapper)pmManager.GetRDMParameterWrapperByID(ERDM_Parameter.SUPPORTED_PARAMETERS); - private static SensorDefinitionParameterWrapper sensorDefinitionParameterWrapper => (SensorDefinitionParameterWrapper)pmManager.GetRDMParameterWrapperByID(ERDM_Parameter.SENSOR_DEFINITION); - - public ushort ManufacturerID { get; private set; } - public EManufacturer Manufacturer { get; private set; } - public UID CurrentUsedUID { get; private set; } + public new bool IsDisposing { get; private set; } + public new bool IsDisposed { get; private set; } - public event EventHandler Initialized; public bool IsInitialized { get; private set; } = false; - private readonly AsyncRDMRequestHelper asyncRDMRequestHelper; - - private readonly ConcurrentDictionary manufacturerParameter = new ConcurrentDictionary(); - - - - private ConcurrentDictionary parameterValues = new ConcurrentDictionary(); - public IReadOnlyDictionary ParameterValues - { - get { return this.parameterValues?.AsReadOnly(); } + public event EventHandler Initialized; + public event PropertyChangedEventHandler PropertyChanged; + + public readonly ushort ManufacturerID; + public readonly EManufacturer Manufacturer; + + private UID currentUsedUID; + public UID CurrentUsedUID + { + get { return currentUsedUID; } + private set + { + if (currentUsedUID == value) + return; + currentUsedUID = value; + PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(CurrentUsedUID))); + } } + private SubDevice currentUsedSubDevice; + public SubDevice CurrentUsedSubDevice + { + get + { + return currentUsedSubDevice; + } + private set + { + if (currentUsedSubDevice == value) + return; + currentUsedSubDevice = value; + PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(CurrentUsedSubDevice))); + } + } + public RDMDeviceInfo DeviceInfo { @@ -59,8 +77,10 @@ private set { if (this.DeviceInfo == value) return; - - this.parameterValues[ERDM_Parameter.DEVICE_INFO] = value; + + var dataTreeBranch = DataTreeBranch.FromObject(value, null, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.DEVICE_INFO); + updateParameterValuesDependeciePropertyBag(ERDM_Parameter.DEVICE_INFO, dataTreeBranch); + updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ERDM_Parameter.DEVICE_INFO), dataTreeBranch); PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(DeviceInfo))); } } @@ -68,148 +88,92 @@ private set private ConcurrentDictionary supportedParameters = new ConcurrentDictionary(); public IReadOnlyCollection SupportedParameters { - get { return this.supportedParameters.Where(sp => sp.Value).Select(sp => sp.Key).Where(p => ((ushort)p > 0x000F)).ToArray().AsReadOnly(); } + get { return this.supportedParameters.Where(sp => sp.Value).Select(sp => sp.Key).Where(p => ((ushort)p > 0x000F)).OrderBy(p => p).ToArray().AsReadOnly(); } } public IReadOnlyCollection SupportedBlueprintParameters { - get { return this.SupportedParameters.Where(p => pmManager.GetRDMParameterWrapperByID(p) is IRDMBlueprintParameterWrapper).ToArray().AsReadOnly(); } + get { return this.SupportedParameters.Intersect(Constants.BLUEPRINT_MODEL_PARAMETERS).OrderBy(p => p).ToList().AsReadOnly(); } } public IReadOnlyCollection SupportedNonBlueprintParameters { - get { return this.SupportedParameters.Where(p => pmManager.GetRDMParameterWrapperByID(p) is not IRDMBlueprintParameterWrapper).ToArray().AsReadOnly(); } + get { return this.SupportedParameters.Except(SupportedBlueprintParameters).OrderBy(p => p).ToList().AsReadOnly(); } } public IReadOnlyCollection KnownNotSupportedParameters { - get { return this.supportedParameters.Where(sp => !sp.Value).Select(sp => sp.Key).ToArray().AsReadOnly(); } + get { return this.supportedParameters.Where(sp => !sp.Value).Select(sp => sp.Key).OrderBy(p => p).ToArray().AsReadOnly(); } } - public bool IsDisposing { get; private set; } - public bool IsDisposed { get; private set; } - - public event PropertyChangedEventHandler PropertyChanged; private readonly Func sendRdmFunktion; - internal RDMDeviceModel(UID uid, RDMDeviceInfo deviceInfo, Func sendRdmFunktion) + internal RDMDeviceModel(UID uid, SubDevice sudevice, RDMDeviceInfo deviceInfo, Func sendRdmFunktion) { this.sendRdmFunktion = sendRdmFunktion; DeviceInfo = deviceInfo; - this.CurrentUsedUID = uid; + CurrentUsedUID = uid; + CurrentUsedSubDevice = sudevice; ManufacturerID = uid.ManufacturerID; Manufacturer = (EManufacturer)uid.ManufacturerID; - - asyncRDMRequestHelper = new AsyncRDMRequestHelper(sendRDMMessage); } internal async Task Initialize() { if (IsInitialized) return; - await processMessage(await requestParameter(supportedParametersParameterWrapper.BuildGetRequestMessage())); - - var sp = this.SupportedParameters.ToArray(); - foreach (ERDM_Parameter parameter in sp) - { - var pw = pmManager.GetRDMParameterWrapperByID(parameter); - - switch (pw) - { - case ParameterDescriptionParameterWrapper parameterDescription: - foreach (ERDM_Parameter p in this.SupportedParameters.Where(p => !ERDM_Parameter.IsDefined(typeof(ERDM_Parameter), p))) - await processMessage(await requestParameter((pw as ParameterDescriptionParameterWrapper).BuildGetRequestMessage(p))); - break; - case SupportedParametersParameterWrapper supportedParameters: - break; - } - - //if (parameter == ERDM_Parameter.SENSOR_DEFINITION) - //{ - // await this.RequestSensorDefinitions(uid); - // continue; - //} - - if (pw is not IRDMBlueprintParameterWrapper) - continue; - - RDMMessage request = null; - if (pw is IRDMBlueprintDescriptionListParameterWrapper blueprintDL) - { - foreach (IRDMParameterWrapper _pm in blueprintDL.DescriptiveParameters.Select(pid => pmManager.GetRDMParameterWrapperByID(pid))) - await doCurrentWrapper(_pm); - //if (blueprintDL.DescriptiveParameters?.Contains(blueprintDL.ValueParameterID) == false) - // await doCurrentWrapper(pmManager.GetRDMParameterWrapperByID(blueprintDL.ValueParameterID)); + asyncRDMRequestHelper = new AsyncRDMRequestHelper(sendRDMMessage); - await doCurrentWrapper(pw); - } - else - await doCurrentWrapper(pw); + await requestSupportedParameters(); + await requestBlueprintParameters(); - async Task doCurrentWrapper(IRDMParameterWrapper wrapper) - { - if (this.parameterValues.ContainsKey(wrapper.Parameter)) - return; - - switch (wrapper) - { - case IRDMGetParameterWrapperWithEmptyGetRequest emptyGet: - request = emptyGet.BuildGetRequestMessage(); - if (request != null) - await processMessage(await requestParameter(request)); - return; - case IRDMGetParameterWrapperRequestRanged getParameter: - await doRange(getParameter); - return; + asyncRDMRequestHelper.Dispose(); + asyncRDMRequestHelper = null; - //case IRDMGetParameterWrapperRequestContravariance getContravarianceByte: - // doRange(getContravarianceByte); - // return; + IsInitialized = true; + Initialized?.Invoke(this, EventArgs.Empty); + } - //case IRDMGetParameterWrapperRequestContravariance getContravarianceObject: - // break; - //case IRDMGetParameterWrapperRequestContravariance getContravarianceObject: - // break; - default: - break; - } + #region Requests + private async Task requestSupportedParameters() + { + ParameterBag parameterBag = new ParameterBag(ERDM_Parameter.SUPPORTED_PARAMETERS); + PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.GET_COMMAND, CurrentUsedUID, CurrentUsedSubDevice, parameterBag); + await runPeerToPeerProcess(ptpProcess); - if (request == null) - return; + if (!ptpProcess.ResponsePayloadObject.IsUnset) + updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(parameterBag.PID), ptpProcess.ResponsePayloadObject); + if (ptpProcess.ResponsePayloadObject.ParsedObject is ERDM_Parameter[] parameters) + { + foreach (var para in parameters) + { + if (!this.supportedParameters.TryGetValue(para, out _)) + supportedParameters.TryAdd(para, true); + } + } + } - await processMessage(await requestParameter(request)); - async Task doRange(IRDMGetParameterWrapperRequestRanged getParameterWrapperRequest) - { - ERDM_Parameter descriptive; - object dVal = null; - IRequestRange range = null; - if (getParameterWrapperRequest is IRDMBlueprintDescriptionListParameterWrapper blueprintDL) - { - descriptive = blueprintDL.DescriptiveParameters.FirstOrDefault(); - if (descriptive != default) - this.parameterValues.TryGetValue(descriptive, out dVal); - } - if (dVal == null) - return; - range = getParameterWrapperRequest.GetRequestRange(dVal); - if (range == null) - return; - foreach (var r in range.ToEnumerator()) - { - request = getParameterWrapperRequest.BuildGetRequestMessage(r); - if (request != null) - await processMessage(await requestParameter(request)); - } - } + private async Task requestBlueprintParameters() + { + foreach (ERDM_Parameter parameter in this.SupportedBlueprintParameters) + { + ParameterBag parameterBag = new ParameterBag(parameter, ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); + var define = MetadataFactory.GetDefine(parameterBag); + if (define.GetRequest.HasValue) + { + if (define.GetRequest.Value.GetIsEmpty()) + await requestParameterWithEmptyPayload(parameterBag, define, CurrentUsedUID, CurrentUsedSubDevice); + else + await requestParameterWithPayload(parameterBag, define, CurrentUsedUID, CurrentUsedSubDevice); } } - IsInitialized = true; - Initialized?.Invoke(this, EventArgs.Empty); } + #endregion + private async Task sendRDMMessage(RDMMessage rdmMessage) { @@ -225,125 +189,7 @@ internal async Task ReceiveRDMMessage(RDMMessage rdmMessage) if (!rdmMessage.Command.HasFlag(ERDM_Command.RESPONSE)) return; - if (asyncRDMRequestHelper.ReceiveMethode(rdmMessage)) - return; - - await processMessage(rdmMessage); - } - - private async Task requestParameter(RDMMessage rdmMessage) - { - return await asyncRDMRequestHelper.RequestParameter(rdmMessage); - } - - private async Task processMessage(RequestResult result) - { - if (IsInitialized) - return; - - if (result.Success) - await processMessage(result.Response); - else if (result.Cancel) - return; - else - { - await Task.Delay(TimeSpan.FromTicks(random.Next(4500, 5500))); - await processMessage(await requestParameter(result.Request)); - } - } - private async Task processMessage(RDMMessage rdmMessage) - { - if (IsInitialized) - return; - - var pw = pmManager.GetRDMParameterWrapperByID(rdmMessage.Parameter); - switch (pw) - { - case SupportedParametersParameterWrapper _supportedParameters: - if (rdmMessage.Value is not ERDM_Parameter[] parameters) - break; - - foreach (var para in parameters) - { - if (!this.supportedParameters.TryGetValue(para, out _)) - supportedParameters.TryAdd(para, true); - } - break; - - case ParameterDescriptionParameterWrapper _parameterDescription when rdmMessage.Value is RDMParameterDescription pd: - if (manufacturerParameter.ContainsKey(pd.ParameterId)) - break; - switch (pd.DataType) - { - case ERDM_DataType.ASCII: - manufacturerParameter.TryAdd(pd.ParameterId, new ASCIIParameterWrapper(pd)); - break; - case ERDM_DataType.SIGNED_BYTE: - manufacturerParameter.TryAdd(pd.ParameterId, new SignedByteParameterWrapper(pd)); - break; - case ERDM_DataType.UNSIGNED_BYTE: - manufacturerParameter.TryAdd(pd.ParameterId, new UnsignedByteParameterWrapper(pd)); - break; - case ERDM_DataType.SIGNED_WORD: - manufacturerParameter.TryAdd(pd.ParameterId, new SignedWordParameterWrapper(pd)); - break; - case ERDM_DataType.UNSIGNED_WORD: - manufacturerParameter.TryAdd(pd.ParameterId, new UnsignedWordParameterWrapper(pd)); - break; - case ERDM_DataType.SIGNED_DWORD: - manufacturerParameter.TryAdd(pd.ParameterId, new SignedDWordParameterWrapper(pd)); - break; - case ERDM_DataType.UNSIGNED_DWORD: - manufacturerParameter.TryAdd(pd.ParameterId, new UnsignedDWordParameterWrapper(pd)); - break; - - case ERDM_DataType.BIT_FIELD: - default: - manufacturerParameter.TryAdd(pd.ParameterId, new NotDefinedParameterWrapper(pd)); - break; - - } - break; - - case IRDMBlueprintDescriptionListParameterWrapper blueprintDL: - ConcurrentDictionary list = null; - if (parameterValues.TryGetValue(rdmMessage.Parameter, out object value)) - list = value as ConcurrentDictionary; - - if (list == null) - parameterValues[rdmMessage.Parameter] = list = new ConcurrentDictionary(); - - if (list == null) - return; - - if (rdmMessage.Value == null) - return; - - if (rdmMessage.Value is IRDMPayloadObjectIndex indexObject) - list.AddOrUpdate(indexObject.Index, rdmMessage.Value, (o, p) => rdmMessage.Value); - - break; - case IRDMBlueprintParameterWrapper blueprint: - parameterValues[rdmMessage.Parameter] = rdmMessage.Value; - break; - default: - if (rdmMessage.Value is IRDMPayloadObjectOneOf oneOf) - { - var bdl = pmManager.ParameterWrappers.OfType().FirstOrDefault(p => p.ValueParameterID == rdmMessage.Parameter); - switch (bdl) - { - case IRDMGetParameterWrapperRequest @byte: - for (byte b = (byte)oneOf.MinIndex; b < (byte)oneOf.Count + (byte)oneOf.MinIndex; b++) - await processMessage(await requestParameter(@byte.BuildGetRequestMessage(b))); - break; - case IRDMGetParameterWrapperRequest @ushort: - for (ushort u = (ushort)oneOf.MinIndex; u < (ushort)oneOf.Count + (ushort)oneOf.MinIndex; u++) - await processMessage(await requestParameter(@ushort.BuildGetRequestMessage(u))); - break; - } - } - break; - } + asyncRDMRequestHelper?.ReceiveMessage(rdmMessage); } public bool IsModelOf(UID uid, RDMDeviceInfo other) @@ -386,28 +232,30 @@ internal void AddParameterToKnownNotSupportedParameters(ERDM_Parameter parameter this.supportedParameters.AddOrUpdate(parameter, false, (x, y) => false); } - public void Dispose() + public new void Dispose() { + if (this.IsDisposed || this.IsDisposing) + return; + this.IsDisposing = true; + this.PropertyChanged = null; + this.Initialized = null; - this.parameterValues.Clear(); - this.parameterValues = null; this.supportedParameters = null; + base.Dispose(); this.IsDisposed = true; + this.IsDisposing = false; } - public RDMSensorDefinition[] GetSensorDefinitions() + public IReadOnlyCollection GetSensorDefinitions() { try { if (!parameterValues.TryGetValue(ERDM_Parameter.SENSOR_DEFINITION, out object value)) return Array.Empty(); else - { - var definitions = value as ConcurrentDictionary; - return definitions.Values.Cast().ToArray(); - } + return value as RDMSensorDefinition[]; } catch { @@ -416,12 +264,6 @@ public RDMSensorDefinition[] GetSensorDefinitions() return Array.Empty(); } - public IRDMParameterWrapper GetRDMParameterWrapperByID(ushort parameter) - { - if (this.manufacturerParameter.TryGetValue(parameter, out var result)) - return result; - return null; - } public override string ToString() { return $"{Enum.GetName(typeof(EManufacturer), Manufacturer)}"; diff --git a/RDMSharp/RDM/Discovery/AbstractDiscoveryTool.cs b/RDMSharp/RDM/Discovery/AbstractDiscoveryTool.cs index 8c18351..826bdee 100644 --- a/RDMSharp/RDM/Discovery/AbstractDiscoveryTool.cs +++ b/RDMSharp/RDM/Discovery/AbstractDiscoveryTool.cs @@ -34,7 +34,7 @@ public AbstractDiscoveryTool() protected void ReceiveRDMMessage(RDMMessage rdmMessage) { - asyncRDMRequestHelper.ReceiveMethode(rdmMessage); + asyncRDMRequestHelper.ReceiveMessage(rdmMessage); } public async Task> PerformDiscovery(IProgress progress = null, bool full = true) @@ -99,7 +99,7 @@ private async Task DiscoverDevicesBinarySearch(UID uidStart, UID uidEnd, RDMDisc ParameterData = new DiscUniqueBranchRequest(uidStart, uidEnd).ToPayloadData() }; context.IncreaseMessageCounter(); - var res = await asyncRDMRequestHelper.RequestParameter(m); + var res = await asyncRDMRequestHelper.RequestMessage(m); if (res.Success) { success = res.Success; @@ -202,7 +202,7 @@ private async Task DiscoverDevicesBinarySearch(UID uidStart, UID uidEnd, RDMDisc Parameter = ERDM_Parameter.DISC_MUTE, DestUID = uid }; - var res = await asyncRDMRequestHelper.RequestParameter(n); + var res = await asyncRDMRequestHelper.RequestMessage(n); if (res.Success) { muted = res.Success; diff --git a/RDMSharp/RDM/Enum/ERDM_BrokerStatus.cs b/RDMSharp/RDM/Enum/ERDM_BrokerStatus.cs index 26b33f8..97d80a8 100644 --- a/RDMSharp/RDM/Enum/ERDM_BrokerStatus.cs +++ b/RDMSharp/RDM/Enum/ERDM_BrokerStatus.cs @@ -1,5 +1,9 @@ -namespace RDMSharp +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp { + [DataTreeEnum(ERDM_Parameter.BROKER_STATUS, Command.ECommandDublicte.SetRequest,"")] public enum ERDM_BrokerStatus : byte { DISABLED = 0x00, diff --git a/RDMSharp/RDM/Enum/ERDM_DisplayInvert.cs b/RDMSharp/RDM/Enum/ERDM_DisplayInvert.cs index 2a58318..c99ab2b 100644 --- a/RDMSharp/RDM/Enum/ERDM_DisplayInvert.cs +++ b/RDMSharp/RDM/Enum/ERDM_DisplayInvert.cs @@ -1,5 +1,10 @@ -namespace RDMSharp +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp { + [DataTreeEnum(ERDM_Parameter.DISPLAY_INVERT, Command.ECommandDublicte.GetResponse, "setting")] + [DataTreeEnum(ERDM_Parameter.DISPLAY_INVERT, Command.ECommandDublicte.SetRequest, "setting")] public enum ERDM_DisplayInvert : byte { OFF = 0x00, diff --git a/RDMSharp/RDM/Enum/ERDM_IdentifyMode.cs b/RDMSharp/RDM/Enum/ERDM_IdentifyMode.cs index 38ba3f8..7b5ff3b 100644 --- a/RDMSharp/RDM/Enum/ERDM_IdentifyMode.cs +++ b/RDMSharp/RDM/Enum/ERDM_IdentifyMode.cs @@ -1,6 +1,11 @@ -namespace RDMSharp +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp { //E1.37-1 + [DataTreeEnum(ERDM_Parameter.IDENTIFY_MODE, Command.ECommandDublicte.GetResponse, "mode")] + [DataTreeEnum(ERDM_Parameter.IDENTIFY_MODE, Command.ECommandDublicte.SetRequest, "mode")] public enum ERDM_IdentifyMode : byte { QUIET = 0x00, diff --git a/RDMSharp/RDM/Enum/ERDM_LampMode.cs b/RDMSharp/RDM/Enum/ERDM_LampMode.cs index e4a9157..845705e 100644 --- a/RDMSharp/RDM/Enum/ERDM_LampMode.cs +++ b/RDMSharp/RDM/Enum/ERDM_LampMode.cs @@ -1,16 +1,19 @@ -using System.ComponentModel; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.ComponentModel; -namespace RDMSharp +namespace RDMSharp; + +[DataTreeEnum(ERDM_Parameter.LAMP_ON_MODE, Command.ECommandDublicte.GetResponse, "mode")] +[DataTreeEnum(ERDM_Parameter.LAMP_ON_MODE, Command.ECommandDublicte.SetRequest, "mode")] +public enum ERDM_LampMode : byte { - public enum ERDM_LampMode : byte - { - [Description("Lamp Stays off until directly instructed to Strike.")] - ON_MODE_OFF = 0x00, - [Description("Lamp Strikes upon receiving a DMX512 signal.")] - ON_MODE_DMX = 0x01, - [Description("Lamp Strikes automatically at Power-up.")] - ON_MODE_ON = 0x02, - [Description("Lamp Strikes after Calibration or Homing procedure.")] - ON_MODE_AFTER_CAL = 0x03, - } -} + [Description("Lamp Stays off until directly instructed to Strike.")] + ON_MODE_OFF = 0x00, + [Description("Lamp Strikes upon receiving a DMX512 signal.")] + ON_MODE_DMX = 0x01, + [Description("Lamp Strikes automatically at Power-up.")] + ON_MODE_ON = 0x02, + [Description("Lamp Strikes after Calibration or Homing procedure.")] + ON_MODE_AFTER_CAL = 0x03, +} \ No newline at end of file diff --git a/RDMSharp/RDM/Enum/ERDM_LampState.cs b/RDMSharp/RDM/Enum/ERDM_LampState.cs index c26ca8c..13553df 100644 --- a/RDMSharp/RDM/Enum/ERDM_LampState.cs +++ b/RDMSharp/RDM/Enum/ERDM_LampState.cs @@ -1,7 +1,11 @@ -using System.ComponentModel; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.ComponentModel; namespace RDMSharp { + [DataTreeEnum(ERDM_Parameter.LAMP_STATE, Command.ECommandDublicte.GetResponse, "state")] + [DataTreeEnum(ERDM_Parameter.LAMP_STATE, Command.ECommandDublicte.SetRequest, "state")] public enum ERDM_LampState : byte { [Description("Off")] diff --git a/RDMSharp/RDM/Enum/ERDM_MergeMode.cs b/RDMSharp/RDM/Enum/ERDM_MergeMode.cs index 940bd48..55bce42 100644 --- a/RDMSharp/RDM/Enum/ERDM_MergeMode.cs +++ b/RDMSharp/RDM/Enum/ERDM_MergeMode.cs @@ -1,5 +1,10 @@ -namespace RDMSharp +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp { + [DataTreeEnum(ERDM_Parameter.PRESET_MERGEMODE, Command.ECommandDublicte.GetResponse, "mode")] + [DataTreeEnum(ERDM_Parameter.PRESET_MERGEMODE, Command.ECommandDublicte.SetRequest, "mode")] public enum ERDM_MergeMode : byte { DEFAULT = 0x00, diff --git a/RDMSharp/RDM/Enum/ERDM_Parameter.cs b/RDMSharp/RDM/Enum/ERDM_Parameter.cs index 5cd25dd..8034c98 100644 --- a/RDMSharp/RDM/Enum/ERDM_Parameter.cs +++ b/RDMSharp/RDM/Enum/ERDM_Parameter.cs @@ -1,8 +1,15 @@ -namespace RDMSharp +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp { /// /// https://www.rdmprotocol.org/rdm/developers/developer-resources/ - /// + /// + [DataTreeEnum(ERDM_Parameter.SUPPORTED_PARAMETERS, Command.ECommandDublicte.GetResponse, "pid", true, "pids")] + [DataTreeEnum(ERDM_Parameter.PARAMETER_DESCRIPTION, Command.ECommandDublicte.GetRequest, "pid")] + [DataTreeEnum(ERDM_Parameter.METADATA_JSON, Command.ECommandDublicte.GetRequest, "pid")] + [DataTreeEnum(ERDM_Parameter.METADATA_PARAMETER_VERSION, Command.ECommandDublicte.GetRequest, "pid")] public enum ERDM_Parameter : ushort { NONE = 0x0000, diff --git a/RDMSharp/RDM/Enum/ERDM_PowerState.cs b/RDMSharp/RDM/Enum/ERDM_PowerState.cs index ab97ecf..df40f43 100644 --- a/RDMSharp/RDM/Enum/ERDM_PowerState.cs +++ b/RDMSharp/RDM/Enum/ERDM_PowerState.cs @@ -1,5 +1,10 @@ -namespace RDMSharp +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp { + [DataTreeEnum(ERDM_Parameter.POWER_STATE, Command.ECommandDublicte.GetResponse, "state")] + [DataTreeEnum(ERDM_Parameter.POWER_STATE, Command.ECommandDublicte.SetRequest, "state")] public enum ERDM_PowerState : byte { FULL_OFF = 0x00, diff --git a/RDMSharp/RDM/Enum/ERDM_ProductDetail.cs b/RDMSharp/RDM/Enum/ERDM_ProductDetail.cs index 57c1be6..c351c53 100644 --- a/RDMSharp/RDM/Enum/ERDM_ProductDetail.cs +++ b/RDMSharp/RDM/Enum/ERDM_ProductDetail.cs @@ -1,5 +1,9 @@ -namespace RDMSharp +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp { + [DataTreeEnum(ERDM_Parameter.PRODUCT_DETAIL_ID_LIST, Command.ECommandDublicte.GetResponse, "product_detail_id", true, "product_detail_ids")] public enum ERDM_ProductDetail : ushort { NONE = 0x0000, diff --git a/RDMSharp/RDM/Enum/ERDM_ResetType.cs b/RDMSharp/RDM/Enum/ERDM_ResetType.cs index 1e74b99..ce8422a 100644 --- a/RDMSharp/RDM/Enum/ERDM_ResetType.cs +++ b/RDMSharp/RDM/Enum/ERDM_ResetType.cs @@ -1,5 +1,9 @@ -namespace RDMSharp +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp { + [DataTreeEnum(ERDM_Parameter.RESET_DEVICE, Command.ECommandDublicte.SetRequest, "state")] public enum ERDM_ResetType : byte { Warm = 0x01, diff --git a/RDMSharp/RDM/Enum/ERDM_ShippingLockState.cs b/RDMSharp/RDM/Enum/ERDM_ShippingLockState.cs index d13a6c0..cfe0d5c 100644 --- a/RDMSharp/RDM/Enum/ERDM_ShippingLockState.cs +++ b/RDMSharp/RDM/Enum/ERDM_ShippingLockState.cs @@ -1,6 +1,11 @@ -namespace RDMSharp +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp { //E1.37-5 + [DataTreeEnum(ERDM_Parameter.SHIPPING_LOCK, Command.ECommandDublicte.GetResponse, "lock_state")] + [DataTreeEnum(ERDM_Parameter.SHIPPING_LOCK, Command.ECommandDublicte.SetRequest, "lock_state")] public enum ERDM_ShippingLockState : byte { /// diff --git a/RDMSharp/RDM/Enum/ERDM_Status.cs b/RDMSharp/RDM/Enum/ERDM_Status.cs index 0607316..e2e286b 100644 --- a/RDMSharp/RDM/Enum/ERDM_Status.cs +++ b/RDMSharp/RDM/Enum/ERDM_Status.cs @@ -1,5 +1,11 @@ -namespace RDMSharp +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; + +namespace RDMSharp { + [DataTreeEnum(ERDM_Parameter.STATUS_MESSAGES, Command.ECommandDublicte.GetRequest, "status_type")] + [DataTreeEnum(ERDM_Parameter.SUB_DEVICE_STATUS_REPORT_THRESHOLD, Command.ECommandDublicte.GetResponse, "status_type")] + [DataTreeEnum(ERDM_Parameter.SUB_DEVICE_STATUS_REPORT_THRESHOLD, Command.ECommandDublicte.SetRequest, "status_type")] public enum ERDM_Status : byte { NONE = 0x00, diff --git a/RDMSharp/RDM/IRDMDeviceModel.cs b/RDMSharp/RDM/IRDMDeviceModel.cs index 4f8ecb0..67aad7c 100644 --- a/RDMSharp/RDM/IRDMDeviceModel.cs +++ b/RDMSharp/RDM/IRDMDeviceModel.cs @@ -10,11 +10,9 @@ public interface IRDMDeviceModel : IDisposable IReadOnlyCollection SupportedBlueprintParameters { get; } IReadOnlyCollection SupportedNonBlueprintParameters { get; } IReadOnlyCollection KnownNotSupportedParameters { get; } - RDMSensorDefinition[] GetSensorDefinitions(); + IReadOnlyCollection GetSensorDefinitions(); IReadOnlyDictionary ParameterValues { get; } - IRDMParameterWrapper GetRDMParameterWrapperByID(ushort parameter); - bool IsDisposing { get; } bool IsDisposed { get; } bool IsModelOf(UID uid, RDMDeviceInfo other); diff --git a/RDMSharp/RDM/PDL.cs b/RDMSharp/RDM/PDL.cs new file mode 100644 index 0000000..e213398 --- /dev/null +++ b/RDMSharp/RDM/PDL.cs @@ -0,0 +1,70 @@ +using System; +using System.Linq; + +namespace RDMSharp.RDM +{ + public readonly struct PDL + { + public const uint MAX_LENGTH = 0xE7 * 0xFF; + public readonly uint? Value { get; } + public readonly uint? MinLength { get; } + public readonly uint? MaxLength { get; } + + public PDL() + { + Value = 0; + } + public PDL(uint value) : this() + { + if (value >= MAX_LENGTH) + throw new ArgumentOutOfRangeException($"The Parameter {nameof(value)} should be in range of 0 - {MAX_LENGTH}"); + + Value = value; + } + public PDL(uint minLength, uint maxLength) : this() + { + if (minLength > MAX_LENGTH) + throw new ArgumentOutOfRangeException($"The Parameter {nameof(minLength)} should be in range of 0 - {MAX_LENGTH}"); + if (maxLength > MAX_LENGTH) + throw new ArgumentOutOfRangeException($"The Parameter {nameof(maxLength)} should be in range of 0 - {MAX_LENGTH}"); + + if (minLength == maxLength) + Value = minLength; + else + { + MinLength = Math.Min(minLength, maxLength); + MaxLength = Math.Max(minLength, maxLength); + Value = null; + } + } + public PDL(params PDL[] pdls) + { + uint value = 0, min = 0, max = 0; + + foreach (PDL pdl in pdls.Where(p => p.Value.HasValue)) + value += pdl.Value.Value; + + foreach (PDL pdl in pdls.Where(p => p.MinLength.HasValue)) + min += pdl.MinLength.Value; + foreach (PDL pdl in pdls.Where(p => p.MaxLength.HasValue)) + max += pdl.MaxLength.Value; + + if (min == max) + Value = Math.Min(MAX_LENGTH, value + min); + else + { + MinLength = Math.Min(MAX_LENGTH, value + Math.Min(min, max)); + MaxLength = Math.Min(MAX_LENGTH, value + Math.Max(min, max)); + Value = null; + } + } + + public bool IsValid(int length) + { + if (Value.HasValue) + return Value == length; + + return MinLength <= length && length <= MaxLength; + } + } +} diff --git a/RDMSharp/RDM/PayloadObject/AcknowledgeTimer.cs b/RDMSharp/RDM/PayloadObject/AcknowledgeTimer.cs index 702611b..6880491 100644 --- a/RDMSharp/RDM/PayloadObject/AcknowledgeTimer.cs +++ b/RDMSharp/RDM/PayloadObject/AcknowledgeTimer.cs @@ -7,7 +7,7 @@ public class AcknowledgeTimer : AbstractRDMPayloadObject { [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2208")] public AcknowledgeTimer( - TimeSpan estimidatedResponseTime = default) : this((ushort)(estimidatedResponseTime.TotalSeconds / 10)) + TimeSpan estimidatedResponseTime = default) : this((ushort)(estimidatedResponseTime.TotalSeconds * 10.0)) { if (estimidatedResponseTime.TotalSeconds / 10 > ushort.MaxValue) throw new ArgumentOutOfRangeException("The Timer is to long for the Resolution of 16-bit ushort"); @@ -16,7 +16,7 @@ private AcknowledgeTimer( ushort _estimidatedResponseTimeRaw = default) { this.estimidatedResponseTimeRaw = _estimidatedResponseTimeRaw; - this.EstimidatedResponseTime = TimeSpan.FromSeconds(this.estimidatedResponseTimeRaw * 10); + this.EstimidatedResponseTime = TimeSpan.FromSeconds(this.estimidatedResponseTimeRaw / 10.0); } public TimeSpan EstimidatedResponseTime { get; private set; } diff --git a/RDMSharp/RDM/PayloadObject/GetBackgroundQueuedStatusPolicyDescriptionResponse.cs b/RDMSharp/RDM/PayloadObject/GetBackgroundQueuedStatusPolicyDescriptionResponse.cs index a7de493..85b5b94 100644 --- a/RDMSharp/RDM/PayloadObject/GetBackgroundQueuedStatusPolicyDescriptionResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetBackgroundQueuedStatusPolicyDescriptionResponse.cs @@ -1,12 +1,16 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION, Command.ECommandDublicte.GetResponse)] public class GetBackgroundQueuedStatusPolicyDescriptionResponse : AbstractRDMPayloadObject, IRDMPayloadObjectIndex - { + { + [DataTreeObjectConstructor] public GetBackgroundQueuedStatusPolicyDescriptionResponse( - byte policyId = 1, - string description = default) + [DataTreeObjectParameter("policy")] byte policyId = 1, + [DataTreeObjectParameter("description")] string description = default) { this.PolicyId = policyId; diff --git a/RDMSharp/RDM/PayloadObject/GetBackgroundQueuedStatusPolicyResponse.cs b/RDMSharp/RDM/PayloadObject/GetBackgroundQueuedStatusPolicyResponse.cs index 26a735c..f08b0a6 100644 --- a/RDMSharp/RDM/PayloadObject/GetBackgroundQueuedStatusPolicyResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetBackgroundQueuedStatusPolicyResponse.cs @@ -1,13 +1,17 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.BACKGROUND_QUEUED_STATUS_POLICY, Command.ECommandDublicte.GetResponse)] public class GetBackgroundQueuedStatusPolicyResponse : AbstractRDMPayloadObjectOneOf - { + { + [DataTreeObjectConstructor] public GetBackgroundQueuedStatusPolicyResponse( - byte policyId = 1, - byte policies = default) + [DataTreeObjectParameter("policy_setting")] byte policyId = 1, + [DataTreeObjectParameter("policy_setting_count")] byte policies = default) { this.PolicyId = policyId; this.Policies = policies; diff --git a/RDMSharp/RDM/PayloadObject/GetBindingAndControlFieldsRequest.cs b/RDMSharp/RDM/PayloadObject/GetBindingAndControlFieldsRequest.cs index d0357fc..a455989 100644 --- a/RDMSharp/RDM/PayloadObject/GetBindingAndControlFieldsRequest.cs +++ b/RDMSharp/RDM/PayloadObject/GetBindingAndControlFieldsRequest.cs @@ -1,12 +1,16 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.BINDING_CONTROL_FIELDS, Command.ECommandDublicte.GetRequest)] public class GetBindingAndControlFieldsRequest : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetBindingAndControlFieldsRequest( - ushort endpointId = default, - UID uid = default) + [DataTreeObjectParameter("endpoint_id")] ushort endpointId = default, + [DataTreeObjectParameter("uid")] UID uid = default) { this.EndpointId = endpointId; this.UID = uid; diff --git a/RDMSharp/RDM/PayloadObject/GetBindingAndControlFieldsResponse.cs b/RDMSharp/RDM/PayloadObject/GetBindingAndControlFieldsResponse.cs index 016e086..e78fe35 100644 --- a/RDMSharp/RDM/PayloadObject/GetBindingAndControlFieldsResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetBindingAndControlFieldsResponse.cs @@ -1,14 +1,18 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.BINDING_CONTROL_FIELDS, Command.ECommandDublicte.GetResponse)] public class GetBindingAndControlFieldsResponse : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetBindingAndControlFieldsResponse( - ushort endpointId = default, - UID uid = default, - ushort controlField = default, - UID bindingUID = default) + [DataTreeObjectParameter("endpoint_id")] ushort endpointId = default, + [DataTreeObjectParameter("uid")] UID uid = default, + [DataTreeObjectParameter("control")] ushort controlField = default, + [DataTreeObjectParameter("binding_uid")] UID bindingUID = default) { this.EndpointId = endpointId; this.UID = uid; diff --git a/RDMSharp/RDM/PayloadObject/GetBrokerStatusResponse.cs b/RDMSharp/RDM/PayloadObject/GetBrokerStatusResponse.cs index 445bfad..a0303fe 100644 --- a/RDMSharp/RDM/PayloadObject/GetBrokerStatusResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetBrokerStatusResponse.cs @@ -1,12 +1,16 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.BROKER_STATUS, Command.ECommandDublicte.GetRequest)] public class GetBrokerStatusResponse : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetBrokerStatusResponse( - bool setAllowed = default, - ERDM_BrokerStatus brokerStatus = default) + [DataTreeObjectParameter("setAllowed")] bool setAllowed = default, + [DataTreeObjectParameter("brokerStatus")] ERDM_BrokerStatus brokerStatus = default) { this.SetAllowed = setAllowed; this.BrokerStatus = brokerStatus; diff --git a/RDMSharp/RDM/PayloadObject/GetCommunicationStatusNullStartCodeResponse.cs b/RDMSharp/RDM/PayloadObject/GetCommunicationStatusNullStartCodeResponse.cs index ee5201d..f3f338c 100644 --- a/RDMSharp/RDM/PayloadObject/GetCommunicationStatusNullStartCodeResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetCommunicationStatusNullStartCodeResponse.cs @@ -1,8 +1,11 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.COMMS_STATUS_NSC, Command.ECommandDublicte.GetResponse)] public class GetCommunicationStatusNullStartCodeResponse : AbstractRDMPayloadObject { public GetCommunicationStatusNullStartCodeResponse( @@ -20,6 +23,34 @@ public GetCommunicationStatusNullStartCodeResponse( MaximumSlotCount = maximumSlotCount; NumberOfPacketsWithAnError = numberOfPacketsWithAnError; } + [DataTreeObjectConstructor] + public GetCommunicationStatusNullStartCodeResponse( + [DataTreeObjectParameter("supported")] bool[] supported, + [DataTreeObjectParameter("additive_checksum")] uint additiveChecksumOfMostRecentPacket, + [DataTreeObjectParameter("packet_count")] uint packetCount, + [DataTreeObjectParameter("most_recent_slot_count")] ushort mostRecentSlotCount, + [DataTreeObjectParameter("min_slot_count")] ushort minimumSlotCount, + [DataTreeObjectParameter("max_slot_count")] ushort maximumSlotCount, + [DataTreeObjectParameter("error_count")] uint numberOfPacketsWithAnError) + { + if (supported[0]) + AdditiveChecksumOfMostRecentPacket = additiveChecksumOfMostRecentPacket; + + if (supported[1]) + PacketCount = packetCount; + + if (supported[2]) + MostRecentSlotCount = mostRecentSlotCount; + + if (supported[3]) + MinimumSlotCount = minimumSlotCount; + + if (supported[4]) + MaximumSlotCount = maximumSlotCount; + + if (supported[5]) + NumberOfPacketsWithAnError = numberOfPacketsWithAnError; + } public uint? AdditiveChecksumOfMostRecentPacket { get; private set; } public uint? PacketCount { get; private set; } diff --git a/RDMSharp/RDM/PayloadObject/GetDeviceInfoOffstageRequest.cs b/RDMSharp/RDM/PayloadObject/GetDeviceInfoOffstageRequest.cs index c6f6986..8c90cb9 100644 --- a/RDMSharp/RDM/PayloadObject/GetDeviceInfoOffstageRequest.cs +++ b/RDMSharp/RDM/PayloadObject/GetDeviceInfoOffstageRequest.cs @@ -1,14 +1,18 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.DEVICE_INFO_OFFSTAGE, Command.ECommandDublicte.GetRequest)] public class GetDeviceInfoOffstageRequest : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetDeviceInfoOffstageRequest( - byte rootPersonality = 1, - ushort subDeviceRequested = 0, - byte subDevicePersonalityRequested = 0) + [DataTreeObjectParameter("root_personality")] byte rootPersonality = 1, + [DataTreeObjectParameter("subdevice")] ushort subDeviceRequested = 0, + [DataTreeObjectParameter("subdevice_personality")] byte subDevicePersonalityRequested = 0) { RootPersonality = rootPersonality; SubDeviceRequested = subDeviceRequested; diff --git a/RDMSharp/RDM/PayloadObject/GetDeviceInfoOffstageResponse.cs b/RDMSharp/RDM/PayloadObject/GetDeviceInfoOffstageResponse.cs index 21357db..d5768a0 100644 --- a/RDMSharp/RDM/PayloadObject/GetDeviceInfoOffstageResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetDeviceInfoOffstageResponse.cs @@ -1,8 +1,11 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.DEVICE_INFO_OFFSTAGE, Command.ECommandDublicte.GetResponse)] public class GetDeviceInfoOffstageResponse : AbstractRDMPayloadObject { public GetDeviceInfoOffstageResponse( @@ -17,6 +20,40 @@ public GetDeviceInfoOffstageResponse( DeviceInfo = deviceInfo; } + [DataTreeObjectConstructor] + public GetDeviceInfoOffstageResponse( + [DataTreeObjectParameter("root_personality")] byte rootPersonality, + [DataTreeObjectParameter("subdevice")] ushort subDeviceRequested, + [DataTreeObjectParameter("subdevice_personality")] byte subDevicePersonalityRequested, + [DataTreeObjectParameter("protocol_major")] byte rdmProtocolVersionMajor, + [DataTreeObjectParameter("protocol_minor")] byte rdmProtocolVersionMinor, + [DataTreeObjectParameter("device_model_id")] ushort deviceModelId, + [DataTreeObjectParameter("product_category")] ushort productCategory, + [DataTreeObjectParameter("software_version_id")] uint softwareVersionId, + [DataTreeObjectParameter("dmx_footprint")] ushort dmx512Footprint, + [DataTreeObjectParameter("current_personality")] byte dmx512CurrentPersonality, + [DataTreeObjectParameter("personality_count")] byte dmx512NumberOfPersonalities, + [DataTreeObjectParameter("dmx_start_address")] ushort dmx512StartAddress, + [DataTreeObjectParameter("sub_device_count")] ushort subDeviceCount, + [DataTreeObjectParameter("sensor_count")] byte sensorCount) + : this(rootPersonality, + subDeviceRequested, + subDevicePersonalityRequested, + new RDMDeviceInfo( + rdmProtocolVersionMajor, + rdmProtocolVersionMinor, + deviceModelId, + productCategory, + softwareVersionId, + dmx512Footprint, + dmx512CurrentPersonality, + dmx512NumberOfPersonalities, + dmx512StartAddress, + subDeviceCount, + sensorCount)) + { + } + public byte RootPersonality { get; private set; } public ushort SubDeviceRequested { get; private set; } public byte SubDevicePersonalityRequested { get; private set; } diff --git a/RDMSharp/RDM/PayloadObject/GetDiscoveryStateResponse.cs b/RDMSharp/RDM/PayloadObject/GetDiscoveryStateResponse.cs index 43881f7..4fead44 100644 --- a/RDMSharp/RDM/PayloadObject/GetDiscoveryStateResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetDiscoveryStateResponse.cs @@ -1,7 +1,10 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.DISCOVERY_STATE, Command.ECommandDublicte.GetResponse)] public class GetDiscoveryStateResponse : AbstractRDMPayloadObject { public GetDiscoveryStateResponse( @@ -14,6 +17,15 @@ public GetDiscoveryStateResponse( this.DiscoveryState = discoveryState; } + [DataTreeObjectConstructor] + public GetDiscoveryStateResponse( + [DataTreeObjectParameter("endpoint_id")] ushort endpointId, + [DataTreeObjectParameter("device_count")] ushort deviceCount, + [DataTreeObjectParameter("state")] byte discoveryState): + this(endpointId, deviceCount, (ERDM_DiscoveryState)discoveryState) + { + } + public ushort EndpointId { get; private set; } public ushort DeviceCount { get; private set; } public ERDM_DiscoveryState DiscoveryState { get; private set; } diff --git a/RDMSharp/RDM/PayloadObject/GetEndpointListResponse.cs b/RDMSharp/RDM/PayloadObject/GetEndpointListResponse.cs index 03d6ffc..f23b38a 100644 --- a/RDMSharp/RDM/PayloadObject/GetEndpointListResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetEndpointListResponse.cs @@ -1,13 +1,19 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.ENDPOINT_LIST, Command.ECommandDublicte.GetResponse, true, "endpoints")] public class GetEndpointListResponse : AbstractRDMPayloadObject { - public GetEndpointListResponse(uint listChangedNumber = 0, params EndpointDescriptor[] endpoints) + [DataTreeObjectConstructor] + public GetEndpointListResponse( + [DataTreeObjectParameter("list_change_number")] uint listChangedNumber = 0, + [DataTreeObjectParameter("endpoints")] params EndpointDescriptor[] endpoints) { this.ListChangedNumber = listChangedNumber; this.Endpoints = endpoints; diff --git a/RDMSharp/RDM/PayloadObject/GetEndpointResponderListChangeResponse.cs b/RDMSharp/RDM/PayloadObject/GetEndpointResponderListChangeResponse.cs index 039fc53..505049d 100644 --- a/RDMSharp/RDM/PayloadObject/GetEndpointResponderListChangeResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetEndpointResponderListChangeResponse.cs @@ -1,12 +1,16 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.ENDPOINT_RESPONDER_LIST_CHANGE, Command.ECommandDublicte.GetResponse)] public class GetEndpointResponderListChangeResponse : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetEndpointResponderListChangeResponse( - ushort endpointId = default, - uint listChangeNumber = default) + [DataTreeObjectParameter("endpoint_id")] ushort endpointId = default, + [DataTreeObjectParameter("list_change_number")] uint listChangeNumber = default) { this.EndpointId = endpointId; this.ListChangeNumber = listChangeNumber; diff --git a/RDMSharp/RDM/PayloadObject/GetEndpointRespondersResponse.cs b/RDMSharp/RDM/PayloadObject/GetEndpointRespondersResponse.cs index ac3ccbe..82b3e12 100644 --- a/RDMSharp/RDM/PayloadObject/GetEndpointRespondersResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetEndpointRespondersResponse.cs @@ -1,12 +1,18 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.ENDPOINT_RESPONDERS, Command.ECommandDublicte.GetResponse)] public class GetEndpointRespondersResponse : AbstractRDMPayloadObject { - public GetEndpointRespondersResponse(uint listChangedNumber = 0, params UID[] uids) + [DataTreeObjectConstructor] + public GetEndpointRespondersResponse( + [DataTreeObjectParameter("list_change_number")] uint listChangedNumber = 0, + [DataTreeObjectParameter("uids")] params UID[] uids) { this.ListChangedNumber = listChangedNumber; this.UIDs = uids; diff --git a/RDMSharp/RDM/PayloadObject/GetEndpointTimingDescriptionResponse.cs b/RDMSharp/RDM/PayloadObject/GetEndpointTimingDescriptionResponse.cs index 8ab79f6..7a2221e 100644 --- a/RDMSharp/RDM/PayloadObject/GetEndpointTimingDescriptionResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetEndpointTimingDescriptionResponse.cs @@ -1,12 +1,16 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.ENDPOINT_TIMING_DESCRIPTION, Command.ECommandDublicte.GetResponse)] public class GetEndpointTimingDescriptionResponse : AbstractRDMPayloadObject, IRDMPayloadObjectIndex - { + { + [DataTreeObjectConstructor] public GetEndpointTimingDescriptionResponse( - byte timingtId = 1, - string description = default) + [DataTreeObjectParameter("setting")] byte timingtId = 1, + [DataTreeObjectParameter("description")] string description = default) { this.TimingId = timingtId; diff --git a/RDMSharp/RDM/PayloadObject/GetEndpointTimingResponse.cs b/RDMSharp/RDM/PayloadObject/GetEndpointTimingResponse.cs index ace20a8..c412999 100644 --- a/RDMSharp/RDM/PayloadObject/GetEndpointTimingResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetEndpointTimingResponse.cs @@ -1,14 +1,18 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.ENDPOINT_TIMING, Command.ECommandDublicte.GetResponse)] public class GetEndpointTimingResponse : AbstractRDMPayloadObjectOneOf - { + { + [DataTreeObjectConstructor] public GetEndpointTimingResponse( - ushort endpointId = default, - byte timingId = 1, - byte timings = default) + [DataTreeObjectParameter("endpoint_id")] ushort endpointId = default, + [DataTreeObjectParameter("setting")] byte timingId = 1, + [DataTreeObjectParameter("setting_count")] byte timings = default) { this.EndpointId = endpointId; this.TimingId = timingId; diff --git a/RDMSharp/RDM/PayloadObject/GetHardwareAddressResponse.cs b/RDMSharp/RDM/PayloadObject/GetHardwareAddressResponse.cs index 406d943..5fb2255 100644 --- a/RDMSharp/RDM/PayloadObject/GetHardwareAddressResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetHardwareAddressResponse.cs @@ -1,12 +1,16 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.INTERFACE_HARDWARE_ADDRESS_TYPE, Command.ECommandDublicte.GetResponse)] public class GetHardwareAddressResponse : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetHardwareAddressResponse( - uint interfaceId = 0, - MACAddress hardwareAddress = default) + [DataTreeObjectParameter("id")] uint interfaceId = 0, + [DataTreeObjectParameter("address")] MACAddress hardwareAddress = default) { this.InterfaceId = interfaceId; this.HardwareAddress = hardwareAddress; diff --git a/RDMSharp/RDM/PayloadObject/GetIPv4CurrentAddressResponse.cs b/RDMSharp/RDM/PayloadObject/GetIPv4CurrentAddressResponse.cs index 1967b54..9876a87 100644 --- a/RDMSharp/RDM/PayloadObject/GetIPv4CurrentAddressResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetIPv4CurrentAddressResponse.cs @@ -1,9 +1,12 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; using System.Net; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.IPV4_CURRENT_ADDRESS, Command.ECommandDublicte.GetResponse)] public class GetIPv4CurrentAddressResponse : AbstractRDMPayloadObject { public GetIPv4CurrentAddressResponse( @@ -20,6 +23,15 @@ public GetIPv4CurrentAddressResponse( this.Netmask = netmask; this.DHCPStatus = dhcpStatus; } + [DataTreeObjectConstructor] + public GetIPv4CurrentAddressResponse( + [DataTreeObjectParameter("id")] uint interfaceId, + [DataTreeObjectParameter("address")] IPv4Address ipAddress, + [DataTreeObjectParameter("netmask")] byte netmask, + [DataTreeObjectParameter("dhcp_status")] byte dhcpStatus) + :this(interfaceId, ipAddress, netmask, (ERDM_DHCPStatusMode)dhcpStatus) + { + } public uint InterfaceId { get; private set; } public IPAddress IPAddress { get; private set; } diff --git a/RDMSharp/RDM/PayloadObject/GetInterfaceListResponse.cs b/RDMSharp/RDM/PayloadObject/GetInterfaceListResponse.cs index d27b8fc..a71d16f 100644 --- a/RDMSharp/RDM/PayloadObject/GetInterfaceListResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetInterfaceListResponse.cs @@ -1,13 +1,17 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.LIST_INTERFACES, Command.ECommandDublicte.GetResponse, true, "interfaces")] public class GetInterfaceListResponse : AbstractRDMPayloadObject { - public GetInterfaceListResponse(params InterfaceDescriptor[] interfaces) + [DataTreeObjectConstructor] + public GetInterfaceListResponse([DataTreeObjectParameter("interfaces")] params InterfaceDescriptor[] interfaces) { this.Interfaces = interfaces; } diff --git a/RDMSharp/RDM/PayloadObject/GetInterfaceNameResponse.cs b/RDMSharp/RDM/PayloadObject/GetInterfaceNameResponse.cs index 49bd95a..6473df2 100644 --- a/RDMSharp/RDM/PayloadObject/GetInterfaceNameResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetInterfaceNameResponse.cs @@ -1,12 +1,16 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.INTERFACE_LABEL, Command.ECommandDublicte.GetResponse)] public class GetInterfaceNameResponse : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetInterfaceNameResponse( - uint interfaceId = 0, - string label = "") + [DataTreeObjectParameter("id")] uint interfaceId = 0, + [DataTreeObjectParameter("label")] string label = "") { this.InterfaceId = interfaceId; diff --git a/RDMSharp/RDM/PayloadObject/GetLockStateResponse.cs b/RDMSharp/RDM/PayloadObject/GetLockStateResponse.cs index a429a89..ad983cd 100644 --- a/RDMSharp/RDM/PayloadObject/GetLockStateResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetLockStateResponse.cs @@ -1,13 +1,17 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.LOCK_STATE, Command.ECommandDublicte.GetResponse)] public class GetLockStateResponse : AbstractRDMPayloadObjectOneOf - { + { + [DataTreeObjectConstructor] public GetLockStateResponse( - byte currentLockStateId = 1, - byte lockStates = 0) + [DataTreeObjectParameter("state")] byte currentLockStateId = 1, + [DataTreeObjectParameter("state_count")] byte lockStates = 0) { this.CurrentLockStateId = currentLockStateId; this.LockStates = lockStates; diff --git a/RDMSharp/RDM/PayloadObject/GetSetComponentScope.cs b/RDMSharp/RDM/PayloadObject/GetSetComponentScope.cs index 39996ca..40ad163 100644 --- a/RDMSharp/RDM/PayloadObject/GetSetComponentScope.cs +++ b/RDMSharp/RDM/PayloadObject/GetSetComponentScope.cs @@ -1,4 +1,6 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -6,16 +8,19 @@ using System.Text; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.COMPONENT_SCOPE, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.COMPONENT_SCOPE, Command.ECommandDublicte.SetRequest)] public class GetSetComponentScope : AbstractRDMPayloadObject - { + { + [DataTreeObjectConstructor] public GetSetComponentScope( - ushort scopeSlot = default, - string scopeString = default, - ERDM_StaticConfig staticConfigType = default, - IPAddress staticBrokerIPv4 = default, - IPAddress staticBrokerIPv6 = default, - ushort staticBrokerPort = default) + [DataTreeObjectParameter("scopeSlot")] ushort scopeSlot = default, + [DataTreeObjectParameter("scopeSlot")] string scopeString = default, + [DataTreeObjectParameter("scopeSlot")] ERDM_StaticConfig staticConfigType = default, + [DataTreeObjectParameter("scopeSlot")] IPAddress staticBrokerIPv4 = default, + [DataTreeObjectParameter("scopeSlot")] IPAddress staticBrokerIPv6 = default, + [DataTreeObjectParameter("scopeSlot")] ushort staticBrokerPort = default) { if (string.IsNullOrWhiteSpace(scopeString)) diff --git a/RDMSharp/RDM/PayloadObject/GetSetEndpointBackgroundDiscovery.cs b/RDMSharp/RDM/PayloadObject/GetSetEndpointBackgroundDiscovery.cs index 14eb81d..5624868 100644 --- a/RDMSharp/RDM/PayloadObject/GetSetEndpointBackgroundDiscovery.cs +++ b/RDMSharp/RDM/PayloadObject/GetSetEndpointBackgroundDiscovery.cs @@ -1,12 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.BACKGROUND_DISCOVERY, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.BACKGROUND_DISCOVERY, Command.ECommandDublicte.SetRequest)] public class GetSetEndpointBackgroundDiscovery : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetSetEndpointBackgroundDiscovery( - ushort endpointId = default, - bool backgroundDiscovery = default) + [DataTreeObjectParameter("endpoint_id")] ushort endpointId = default, + [DataTreeObjectParameter("enabled")] bool backgroundDiscovery = default) { this.EndpointId = endpointId; this.BackgroundDiscovery = backgroundDiscovery; diff --git a/RDMSharp/RDM/PayloadObject/GetSetEndpointIdentify.cs b/RDMSharp/RDM/PayloadObject/GetSetEndpointIdentify.cs index a9faf8b..cdb0248 100644 --- a/RDMSharp/RDM/PayloadObject/GetSetEndpointIdentify.cs +++ b/RDMSharp/RDM/PayloadObject/GetSetEndpointIdentify.cs @@ -1,12 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.IDENTIFY_ENDPOINT, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.IDENTIFY_ENDPOINT, Command.ECommandDublicte.SetRequest)] public class GetSetIdentifyEndpoint : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetSetIdentifyEndpoint( - ushort endpointId = default, - bool identifyState = default) + [DataTreeObjectParameter("endpoint_id")] ushort endpointId = default, + [DataTreeObjectParameter("identify_state")] bool identifyState = default) { this.EndpointId = endpointId; this.IdentifyState = identifyState; diff --git a/RDMSharp/RDM/PayloadObject/GetSetEndpointLabel.cs b/RDMSharp/RDM/PayloadObject/GetSetEndpointLabel.cs index ef64ccf..9e242b8 100644 --- a/RDMSharp/RDM/PayloadObject/GetSetEndpointLabel.cs +++ b/RDMSharp/RDM/PayloadObject/GetSetEndpointLabel.cs @@ -1,12 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.ENDPOINT_LABEL, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.ENDPOINT_LABEL, Command.ECommandDublicte.SetRequest)] public class GetSetEndpointLabel : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetSetEndpointLabel( - ushort endpointId = default, - string endpointLabel = default) + [DataTreeObjectParameter("endpoint_id")] ushort endpointId = default, + [DataTreeObjectParameter("label")] string endpointLabel = default) { this.EndpointId = endpointId; diff --git a/RDMSharp/RDM/PayloadObject/GetSetEndpointMode.cs b/RDMSharp/RDM/PayloadObject/GetSetEndpointMode.cs index bf80773..419ad41 100644 --- a/RDMSharp/RDM/PayloadObject/GetSetEndpointMode.cs +++ b/RDMSharp/RDM/PayloadObject/GetSetEndpointMode.cs @@ -1,7 +1,11 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.ENDPOINT_MODE, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.ENDPOINT_MODE, Command.ECommandDublicte.SetRequest)] public class GetSetEndpointMode : AbstractRDMPayloadObject { public GetSetEndpointMode( @@ -12,6 +16,14 @@ public GetSetEndpointMode( this.EndpointMode = endpointMode; } + [DataTreeObjectConstructor] + public GetSetEndpointMode( + [DataTreeObjectParameter("endpoint_id")] ushort endpointId = default, + [DataTreeObjectParameter("mode")] byte endpointMode = default): + this(endpointId, (ERDM_EndpointMode)endpointMode) + { + } + public ushort EndpointId { get; private set; } public ERDM_EndpointMode EndpointMode { get; private set; } public const int PDL = 0x03; diff --git a/RDMSharp/RDM/PayloadObject/GetSetEndpointRDMTrafficEnable.cs b/RDMSharp/RDM/PayloadObject/GetSetEndpointRDMTrafficEnable.cs index 622d27a..31340cb 100644 --- a/RDMSharp/RDM/PayloadObject/GetSetEndpointRDMTrafficEnable.cs +++ b/RDMSharp/RDM/PayloadObject/GetSetEndpointRDMTrafficEnable.cs @@ -1,12 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.RDM_TRAFFIC_ENABLE, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.RDM_TRAFFIC_ENABLE, Command.ECommandDublicte.SetRequest)] public class GetSetEndpointRDMTrafficEnable : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetSetEndpointRDMTrafficEnable( - ushort endpointId = default, - bool rdmTrafficEnabled = default) + [DataTreeObjectParameter("endpoint_id")] ushort endpointId = default, + [DataTreeObjectParameter("rdm_enabled")] bool rdmTrafficEnabled = default) { this.EndpointId = endpointId; this.RDMTrafficEnabled = rdmTrafficEnabled; diff --git a/RDMSharp/RDM/PayloadObject/GetSetEndpointToUniverse.cs b/RDMSharp/RDM/PayloadObject/GetSetEndpointToUniverse.cs index f14fa54..1b43796 100644 --- a/RDMSharp/RDM/PayloadObject/GetSetEndpointToUniverse.cs +++ b/RDMSharp/RDM/PayloadObject/GetSetEndpointToUniverse.cs @@ -1,12 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.ENDPOINT_TO_UNIVERSE, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.ENDPOINT_TO_UNIVERSE, Command.ECommandDublicte.SetRequest)] public class GetSetEndpointToUniverse : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetSetEndpointToUniverse( - ushort endpointId = default, - ushort universe = default) + [DataTreeObjectParameter("endpoint_id")] ushort endpointId = default, + [DataTreeObjectParameter("universe")] ushort universe = default) { this.EndpointId = endpointId; this.Universe = universe; diff --git a/RDMSharp/RDM/PayloadObject/GetSetIPV4_xxx_Mode.cs b/RDMSharp/RDM/PayloadObject/GetSetIPV4_xxx_Mode.cs index 1dd9307..e1a8b21 100644 --- a/RDMSharp/RDM/PayloadObject/GetSetIPV4_xxx_Mode.cs +++ b/RDMSharp/RDM/PayloadObject/GetSetIPV4_xxx_Mode.cs @@ -1,12 +1,19 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.IPV4_DHCP_MODE, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.IPV4_DHCP_MODE, Command.ECommandDublicte.SetRequest)] + [DataTreeObject(ERDM_Parameter.IPV4_ZEROCONF_MODE, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.IPV4_ZEROCONF_MODE, Command.ECommandDublicte.SetRequest)] public class GetSetIPV4_xxx_Mode : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetSetIPV4_xxx_Mode( - uint interfaceId = 0, - bool enabled = false) + [DataTreeObjectParameter("id")] uint interfaceId = 0, + [DataTreeObjectParameter("mode")] bool enabled = false) { this.InterfaceId = interfaceId; this.Enabled = enabled; diff --git a/RDMSharp/RDM/PayloadObject/GetSetIPv4DefaultRoute.cs b/RDMSharp/RDM/PayloadObject/GetSetIPv4DefaultRoute.cs index a53a874..1826d4b 100644 --- a/RDMSharp/RDM/PayloadObject/GetSetIPv4DefaultRoute.cs +++ b/RDMSharp/RDM/PayloadObject/GetSetIPv4DefaultRoute.cs @@ -1,12 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.IPV4_DEFAULT_ROUTE, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.IPV4_DEFAULT_ROUTE, Command.ECommandDublicte.SetRequest)] public class GetSetIPv4DefaultRoute : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetSetIPv4DefaultRoute( - uint interfaceId = 0, - IPv4Address ipAddress = default) + [DataTreeObjectParameter("id")] uint interfaceId = 0, + [DataTreeObjectParameter("default_route")] IPv4Address ipAddress = default) { this.InterfaceId = interfaceId; this.IPAddress = ipAddress; diff --git a/RDMSharp/RDM/PayloadObject/GetSetIPv4NameServer.cs b/RDMSharp/RDM/PayloadObject/GetSetIPv4NameServer.cs index f9b4689..9ab8fd3 100644 --- a/RDMSharp/RDM/PayloadObject/GetSetIPv4NameServer.cs +++ b/RDMSharp/RDM/PayloadObject/GetSetIPv4NameServer.cs @@ -1,12 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.DNS_IPV4_NAME_SERVER, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.DNS_IPV4_NAME_SERVER, Command.ECommandDublicte.SetRequest)] public class GetSetIPv4NameServer : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetSetIPv4NameServer( - byte nameServerIndex = 0, - IPv4Address ipAddress = default) + [DataTreeObjectParameter("index")] byte nameServerIndex = 0, + [DataTreeObjectParameter("address")] IPv4Address ipAddress = default) { this.NameServerIndex = nameServerIndex; this.IPAddress = ipAddress; diff --git a/RDMSharp/RDM/PayloadObject/GetSetIPv4StaticAddress.cs b/RDMSharp/RDM/PayloadObject/GetSetIPv4StaticAddress.cs index 1a58020..fef4493 100644 --- a/RDMSharp/RDM/PayloadObject/GetSetIPv4StaticAddress.cs +++ b/RDMSharp/RDM/PayloadObject/GetSetIPv4StaticAddress.cs @@ -1,14 +1,19 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.IPV4_STATIC_ADDRESS, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.IPV4_STATIC_ADDRESS, Command.ECommandDublicte.SetRequest)] public class GetSetIPv4StaticAddress : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public GetSetIPv4StaticAddress( - uint interfaceId = 0, - IPv4Address ipAddress = default, - byte netmask = 24) + [DataTreeObjectParameter("id")] uint interfaceId = 0, + [DataTreeObjectParameter("address")] IPv4Address ipAddress = default, + [DataTreeObjectParameter("netmask")] byte netmask = 24) { this.InterfaceId = interfaceId; this.IPAddress = ipAddress; diff --git a/RDMSharp/RDM/PayloadObject/RDMCommunicationStatus.cs b/RDMSharp/RDM/PayloadObject/RDMCommunicationStatus.cs index ccd226c..417b56c 100644 --- a/RDMSharp/RDM/PayloadObject/RDMCommunicationStatus.cs +++ b/RDMSharp/RDM/PayloadObject/RDMCommunicationStatus.cs @@ -1,14 +1,18 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.COMMS_STATUS, Command.ECommandDublicte.GetResponse)] public class RDMCommunicationStatus : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public RDMCommunicationStatus( - ushort shortMessage = 0, - ushort lengthMismatch = 0, - ushort checksumFail = 0) + [DataTreeObjectParameter("short_message")] ushort shortMessage = 0, + [DataTreeObjectParameter("length_mismatch")] ushort lengthMismatch = 0, + [DataTreeObjectParameter("checksum_fail")] ushort checksumFail = 0) { this.ShortMessage = shortMessage; this.LengthMismatch = lengthMismatch; diff --git a/RDMSharp/RDM/PayloadObject/RDMCurve.cs b/RDMSharp/RDM/PayloadObject/RDMCurve.cs index 1a0a003..a68a561 100644 --- a/RDMSharp/RDM/PayloadObject/RDMCurve.cs +++ b/RDMSharp/RDM/PayloadObject/RDMCurve.cs @@ -1,13 +1,17 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.CURVE, Command.ECommandDublicte.GetResponse)] public class RDMCurve : AbstractRDMPayloadObjectOneOf - { + { + [DataTreeObjectConstructor] public RDMCurve( - byte currentCurveId = 1, - byte curves = 0) + [DataTreeObjectParameter("curve")] byte currentCurveId = 1, + [DataTreeObjectParameter("curve_count")] byte curves = 0) { this.CurrentCurveId = currentCurveId; this.Curves = curves; diff --git a/RDMSharp/RDM/PayloadObject/RDMCurveDescription.cs b/RDMSharp/RDM/PayloadObject/RDMCurveDescription.cs index ed4b66a..43fae13 100644 --- a/RDMSharp/RDM/PayloadObject/RDMCurveDescription.cs +++ b/RDMSharp/RDM/PayloadObject/RDMCurveDescription.cs @@ -1,12 +1,16 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.CURVE_DESCRIPTION, Command.ECommandDublicte.GetResponse)] public class RDMCurveDescription : AbstractRDMPayloadObject, IRDMPayloadObjectIndex - { + { + [DataTreeObjectConstructor] public RDMCurveDescription( - byte curveId = 1, - string description = "") + [DataTreeObjectParameter("curve")] byte curveId = 1, + [DataTreeObjectParameter("description")] string description = "") { this.CurveId = curveId; diff --git a/RDMSharp/RDM/PayloadObject/RDMDMXBlockAddress.cs b/RDMSharp/RDM/PayloadObject/RDMDMXBlockAddress.cs index 78a4888..ba28802 100644 --- a/RDMSharp/RDM/PayloadObject/RDMDMXBlockAddress.cs +++ b/RDMSharp/RDM/PayloadObject/RDMDMXBlockAddress.cs @@ -1,13 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.DMX_BLOCK_ADDRESS, Command.ECommandDublicte.GetResponse)] public class RDMDMXBlockAddress : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public RDMDMXBlockAddress( - ushort totalSubDeviceFootprint = 0, - ushort baseDMX512Address = 0) + [DataTreeObjectParameter("total_subdevice_footprint")] ushort totalSubDeviceFootprint = 0, + [DataTreeObjectParameter("base_dmx_address")] ushort baseDMX512Address = 0) { this.TotalSubDeviceFootprint = totalSubDeviceFootprint; this.BaseDMX512Address = baseDMX512Address; diff --git a/RDMSharp/RDM/PayloadObject/RDMDMXPersonality.cs b/RDMSharp/RDM/PayloadObject/RDMDMXPersonality.cs index 01025b2..dd1e7ad 100644 --- a/RDMSharp/RDM/PayloadObject/RDMDMXPersonality.cs +++ b/RDMSharp/RDM/PayloadObject/RDMDMXPersonality.cs @@ -1,19 +1,26 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.DMX_PERSONALITY, Command.ECommandDublicte.GetResponse)] public class RDMDMXPersonality : AbstractRDMPayloadObjectOneOf - { + { + [DataTreeObjectConstructor] public RDMDMXPersonality( - byte currentPersonality = 1, - byte ofPersonalities = 0) + [DataTreeObjectParameter("personality")] byte currentPersonality = 1, + [DataTreeObjectParameter("personality_count")] byte ofPersonalities = 0) { this.CurrentPersonality = currentPersonality; this.OfPersonalities = ofPersonalities; } + [DataTreeObjectProperty("personality", 0)] public byte CurrentPersonality { get; private set; } + + [DataTreeObjectProperty("personality_count", 1)] public byte OfPersonalities { get; private set; } public override Type IndexType => CurrentPersonality.GetType(); diff --git a/RDMSharp/RDM/PayloadObject/RDMDMXPersonalityDescription.cs b/RDMSharp/RDM/PayloadObject/RDMDMXPersonalityDescription.cs index 9b4c2e5..d267bfb 100644 --- a/RDMSharp/RDM/PayloadObject/RDMDMXPersonalityDescription.cs +++ b/RDMSharp/RDM/PayloadObject/RDMDMXPersonalityDescription.cs @@ -1,13 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION, Command.ECommandDublicte.GetResponse)] public class RDMDMXPersonalityDescription : AbstractRDMPayloadObject, IRDMPayloadObjectIndex - { + { + [DataTreeObjectConstructor] public RDMDMXPersonalityDescription( - byte personalityId = 1, - ushort slots = 0, - string description = "") + [DataTreeObjectParameter("personality")] byte personalityId = 1, + [DataTreeObjectParameter("dmx_slots_required")] ushort slots = 0, + [DataTreeObjectParameter("description")] string description = "") { this.PersonalityId = personalityId; this.Slots = slots; @@ -19,10 +23,17 @@ public RDMDMXPersonalityDescription( description = description.Substring(0, 32); this.Description = description; - } - - public byte PersonalityId { get; private set; } - public ushort Slots { get; private set; } + } + + + [DataTreeObjectProperty("personality", 0)] + public byte PersonalityId { get; private set; } + + [DataTreeObjectDependecieProperty("slot", ERDM_Parameter.SLOT_DESCRIPTION, Command.ECommandDublicte.GetRequest)] + [DataTreeObjectProperty("dmx_slots_required", 1)] + public ushort Slots { get; private set; } + + [DataTreeObjectProperty("description", 2)] public string Description { get; private set; } public object MinIndex => (byte)1; diff --git a/RDMSharp/RDM/PayloadObject/RDMDMX_xxxx_Mode.cs b/RDMSharp/RDM/PayloadObject/RDMDMX_xxxx_Mode.cs index da8c13c..b06c870 100644 --- a/RDMSharp/RDM/PayloadObject/RDMDMX_xxxx_Mode.cs +++ b/RDMSharp/RDM/PayloadObject/RDMDMX_xxxx_Mode.cs @@ -1,15 +1,22 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.DMX_FAIL_MODE, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.DMX_FAIL_MODE, Command.ECommandDublicte.SetRequest)] + [DataTreeObject(ERDM_Parameter.DMX_STARTUP_MODE, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.DMX_STARTUP_MODE, Command.ECommandDublicte.SetRequest)] public class RDMDMX_xxxx_Mode : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public RDMDMX_xxxx_Mode( - ushort scene = 0, - ushort delay = 0, - ushort holdTime = 0, - byte level = 0) + [DataTreeObjectParameter("scene_num")] ushort scene = 0, + [DataTreeObjectParameter(ERDM_Parameter.DMX_FAIL_MODE, "loss_of_signal_delay_time"), DataTreeObjectParameter(ERDM_Parameter.DMX_STARTUP_MODE, "startup_delay_time")] ushort delay = 0, + [DataTreeObjectParameter("hold_time")] ushort holdTime = 0, + [DataTreeObjectParameter("level")] byte level = 0) { this.Scene = scene; this.Delay = delay; diff --git a/RDMSharp/RDM/PayloadObject/RDMDefaultSlotValue.cs b/RDMSharp/RDM/PayloadObject/RDMDefaultSlotValue.cs index 2264797..5f87484 100644 --- a/RDMSharp/RDM/PayloadObject/RDMDefaultSlotValue.cs +++ b/RDMSharp/RDM/PayloadObject/RDMDefaultSlotValue.cs @@ -1,19 +1,25 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.DEFAULT_SLOT_VALUE, Command.ECommandDublicte.GetResponse, true, "slots")] public class RDMDefaultSlotValue : AbstractRDMPayloadObject - { + { + [DataTreeObjectConstructor] public RDMDefaultSlotValue( - ushort slotOffset = 0, - byte defaultSlotValue = 0) + [DataTreeObjectParameter("id")] ushort slotOffset = 0, + [DataTreeObjectParameter("default_value")] byte defaultSlotValue = 0) { this.SlotOffset = slotOffset; this.DefaultSlotValue = defaultSlotValue; - } - - public ushort SlotOffset { get; private set; } + } + + [DataTreeObjectProperty("id", 0)] + public ushort SlotOffset { get; private set; } + [DataTreeObjectProperty("default_value", 1)] public byte DefaultSlotValue { get; private set; } public const int PDL = 3; diff --git a/RDMSharp/RDM/PayloadObject/RDMDeviceInfo.cs b/RDMSharp/RDM/PayloadObject/RDMDeviceInfo.cs index a720f27..c84e673 100644 --- a/RDMSharp/RDM/PayloadObject/RDMDeviceInfo.cs +++ b/RDMSharp/RDM/PayloadObject/RDMDeviceInfo.cs @@ -1,8 +1,11 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.DEVICE_INFO, Command.ECommandDublicte.GetResponse)] public class RDMDeviceInfo : AbstractRDMPayloadObject { public RDMDeviceInfo( @@ -32,19 +35,74 @@ public RDMDeviceInfo( SubDeviceCount = subDeviceCount; SensorCount = sensorCount; } + [DataTreeObjectConstructor] + public RDMDeviceInfo( + [DataTreeObjectParameter("protocol_major")] byte rdmProtocolVersionMajor, + [DataTreeObjectParameter("protocol_minor")] byte rdmProtocolVersionMinor, + [DataTreeObjectParameter("device_model_id")] ushort deviceModelId, + [DataTreeObjectParameter("product_category")] ushort productCategory, + [DataTreeObjectParameter("software_version_id")] uint softwareVersionId, + [DataTreeObjectParameter("dmx_footprint")] ushort dmx512Footprint, + [DataTreeObjectParameter("current_personality")] byte dmx512CurrentPersonality, + [DataTreeObjectParameter("personality_count")] byte dmx512NumberOfPersonalities, + [DataTreeObjectParameter("dmx_start_address")] ushort dmx512StartAddress, + [DataTreeObjectParameter("sub_device_count")] ushort subDeviceCount, + [DataTreeObjectParameter("sensor_count")] byte sensorCount): + this(rdmProtocolVersionMajor, + rdmProtocolVersionMinor, + deviceModelId, + (ERDM_ProductCategoryCoarse)(byte)(productCategory >> 8), + (ERDM_ProductCategoryFine)productCategory, + softwareVersionId, + dmx512Footprint, + dmx512CurrentPersonality, + dmx512NumberOfPersonalities, + dmx512StartAddress, + subDeviceCount, + sensorCount) + { + } + [DataTreeObjectProperty("protocol_major", 0)] public byte RdmProtocolVersionMajor { get; private set; } + + [DataTreeObjectProperty("protocol_minor", 1)] public byte RdmProtocolVersionMinor { get; private set; } + + [DataTreeObjectProperty("device_model_id", 2)] public ushort DeviceModelId { get; private set; } public ERDM_ProductCategoryCoarse ProductCategoryCoarse { get; private set; } public ERDM_ProductCategoryFine ProductCategoryFine { get; private set; } + + [DataTreeObjectProperty("product_category", 3)] + public ushort ProductCategory => (ushort)ProductCategoryFine; + + [DataTreeObjectProperty("software_version_id", 4)] public uint SoftwareVersionId { get; private set; } + + [DataTreeObjectDependecieProperty("slot", ERDM_Parameter.SLOT_DESCRIPTION, Command.ECommandDublicte.GetRequest)] + [DataTreeObjectProperty("dmx_footprint", 5)] public ushort? Dmx512Footprint { get; private set; } + + [DataTreeObjectProperty("current_personality", 6)] public byte? Dmx512CurrentPersonality { get; private set; } + + [DataTreeObjectDependecieProperty("personality", ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION, Command.ECommandDublicte.GetRequest)] + [DataTreeObjectDependecieProperty("personality", ERDM_Parameter.DMX_PERSONALITY_ID, Command.ECommandDublicte.GetRequest)] + [DataTreeObjectProperty("personality_count", 7)] public byte Dmx512NumberOfPersonalities { get; private set; } + + [DataTreeObjectProperty("dmx_start_address", 8)] public ushort? Dmx512StartAddress { get; private set; } + + [DataTreeObjectProperty("sub_device_count", 9)] public ushort SubDeviceCount { get; private set; } + + [DataTreeObjectDependecieProperty("sensor", ERDM_Parameter.SENSOR_DEFINITION, Command.ECommandDublicte.GetRequest)] + [DataTreeObjectDependecieProperty("sensor", ERDM_Parameter.SENSOR_VALUE, Command.ECommandDublicte.GetRequest)] + [DataTreeObjectProperty("sensor_count", 10)] public byte SensorCount { get; private set; } + public const int PDL = 19; public override string ToString() diff --git a/RDMSharp/RDM/PayloadObject/RDMDimmerInfo.cs b/RDMSharp/RDM/PayloadObject/RDMDimmerInfo.cs index d576232..7b159b4 100644 --- a/RDMSharp/RDM/PayloadObject/RDMDimmerInfo.cs +++ b/RDMSharp/RDM/PayloadObject/RDMDimmerInfo.cs @@ -1,19 +1,23 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.DIMMER_INFO, Command.ECommandDublicte.GetResponse)] public class RDMDimmerInfo : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public RDMDimmerInfo( - ushort minimumLevelLowerLimit = 0xFFFF, - ushort minimumLevelUpperLimit = 0xFFFF, - ushort maximumLevelLowerLimit = 0xFFFF, - ushort maximumLevelUpperLimit = 0xFFFF, - byte numberOfSupportedCurves = 0, - byte levelsResolution = 1, - bool minimumLevelSplitLevelsSupported = false) + [DataTreeObjectParameter("min_level_lower_limit")] ushort minimumLevelLowerLimit = 0xFFFF, + [DataTreeObjectParameter("min_level_upper_limit")] ushort minimumLevelUpperLimit = 0xFFFF, + [DataTreeObjectParameter("max_level_lower_limit")] ushort maximumLevelLowerLimit = 0xFFFF, + [DataTreeObjectParameter("max_level_upper_limit")] ushort maximumLevelUpperLimit = 0xFFFF, + [DataTreeObjectParameter("curve_count")] byte numberOfSupportedCurves = 0, + [DataTreeObjectParameter("levels_resolution_bits")] byte levelsResolution = 1, + [DataTreeObjectParameter("min_level_split_levels_supported")] bool minimumLevelSplitLevelsSupported = false) { if (levelsResolution < 0x01 || levelsResolution > 0x10) throw new ArgumentOutOfRangeException($"{nameof(levelsResolution)} shold be a value between 1 and 31 but is {levelsResolution}"); diff --git a/RDMSharp/RDM/PayloadObject/RDMLockStateDescription.cs b/RDMSharp/RDM/PayloadObject/RDMLockStateDescription.cs index 73c63e0..df36ff7 100644 --- a/RDMSharp/RDM/PayloadObject/RDMLockStateDescription.cs +++ b/RDMSharp/RDM/PayloadObject/RDMLockStateDescription.cs @@ -1,12 +1,16 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.LOCK_STATE_DESCRIPTION, Command.ECommandDublicte.GetResponse)] public class RDMLockStateDescription : AbstractRDMPayloadObject, IRDMPayloadObjectIndex - { + { + [DataTreeObjectConstructor] public RDMLockStateDescription( - byte lockStateId = 1, - string description = "") + [DataTreeObjectParameter("state")] byte lockStateId = 1, + [DataTreeObjectParameter("description")] string description = "") { this.LockStateId = lockStateId; diff --git a/RDMSharp/RDM/PayloadObject/RDMMetadataJson.cs b/RDMSharp/RDM/PayloadObject/RDMMetadataJson.cs index b491b9e..6e9f73c 100644 --- a/RDMSharp/RDM/PayloadObject/RDMMetadataJson.cs +++ b/RDMSharp/RDM/PayloadObject/RDMMetadataJson.cs @@ -1,13 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.METADATA_JSON, Command.ECommandDublicte.GetResponse)] public class RDMMetadataJson : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public RDMMetadataJson( - ERDM_Parameter parameterId, - string json) + [DataTreeObjectParameter("pid")] ERDM_Parameter parameterId, + [DataTreeObjectParameter("json")] string json) { this.ParameterId = parameterId; this.JSON = json; diff --git a/RDMSharp/RDM/PayloadObject/RDMMetadataParameterVersion.cs b/RDMSharp/RDM/PayloadObject/RDMMetadataParameterVersion.cs index 66a98df..dc6c72f 100644 --- a/RDMSharp/RDM/PayloadObject/RDMMetadataParameterVersion.cs +++ b/RDMSharp/RDM/PayloadObject/RDMMetadataParameterVersion.cs @@ -1,13 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.METADATA_PARAMETER_VERSION, Command.ECommandDublicte.GetResponse)] public class RDMMetadataParameterVersion : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public RDMMetadataParameterVersion( - ERDM_Parameter parameterId, - ushort version) + [DataTreeObjectParameter("pid")] ERDM_Parameter parameterId, + [DataTreeObjectParameter("version")] ushort version) { this.ParameterId = parameterId; this.Version = version; diff --git a/RDMSharp/RDM/PayloadObject/RDMMinimumLevel.cs b/RDMSharp/RDM/PayloadObject/RDMMinimumLevel.cs index 3285331..ca11a86 100644 --- a/RDMSharp/RDM/PayloadObject/RDMMinimumLevel.cs +++ b/RDMSharp/RDM/PayloadObject/RDMMinimumLevel.cs @@ -1,14 +1,19 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.MINIMUM_LEVEL, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.MINIMUM_LEVEL, Command.ECommandDublicte.SetRequest)] public class RDMMinimumLevel : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public RDMMinimumLevel( - ushort minimumLevelIncrease = 0, - ushort minimumLevelDecrease = 0, - bool onBelowMinimum = false) + [DataTreeObjectParameter("min_level_increasing")] ushort minimumLevelIncrease = 0, + [DataTreeObjectParameter("min_level_decreasing")] ushort minimumLevelDecrease = 0, + [DataTreeObjectParameter("on_below_min")] bool onBelowMinimum = false) { this.MinimumLevelIncrease = minimumLevelIncrease; this.MinimumLevelDecrease = minimumLevelDecrease; diff --git a/RDMSharp/RDM/PayloadObject/RDMModulationFrequency.cs b/RDMSharp/RDM/PayloadObject/RDMModulationFrequency.cs index c23ef28..382a20f 100644 --- a/RDMSharp/RDM/PayloadObject/RDMModulationFrequency.cs +++ b/RDMSharp/RDM/PayloadObject/RDMModulationFrequency.cs @@ -1,13 +1,17 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.MODULATION_FREQUENCY, Command.ECommandDublicte.GetResponse)] public class RDMModulationFrequency : AbstractRDMPayloadObjectOneOf - { + { + [DataTreeObjectConstructor] public RDMModulationFrequency( - byte modulationFrequencyId = 1, - byte modulationFrequencys = 0) + [DataTreeObjectParameter("setting")] byte modulationFrequencyId = 1, + [DataTreeObjectParameter("uint8")] byte modulationFrequencys = 0) { this.ModulationFrequencyId = modulationFrequencyId; this.ModulationFrequencys = modulationFrequencys; diff --git a/RDMSharp/RDM/PayloadObject/RDMModulationFrequencyDescription.cs b/RDMSharp/RDM/PayloadObject/RDMModulationFrequencyDescription.cs index b9bd7eb..1fbd6c2 100644 --- a/RDMSharp/RDM/PayloadObject/RDMModulationFrequencyDescription.cs +++ b/RDMSharp/RDM/PayloadObject/RDMModulationFrequencyDescription.cs @@ -1,13 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.MODULATION_FREQUENCY_DESCRIPTION, Command.ECommandDublicte.GetResponse)] public class RDMModulationFrequencyDescription : AbstractRDMPayloadObject, IRDMPayloadObjectIndex - { + { + [DataTreeObjectConstructor] public RDMModulationFrequencyDescription( - byte modulationFrequencyId = 1, - uint? frequency = null, - string description = "") + [DataTreeObjectParameter("setting")] byte modulationFrequencyId = 1, + [DataTreeObjectParameter("frequency")] uint? frequency = null, + [DataTreeObjectParameter("description")] string description = "") { this.ModulationFrequencyId = modulationFrequencyId; diff --git a/RDMSharp/RDM/PayloadObject/RDMOutputResponseTime.cs b/RDMSharp/RDM/PayloadObject/RDMOutputResponseTime.cs index 2e33f3a..d832d56 100644 --- a/RDMSharp/RDM/PayloadObject/RDMOutputResponseTime.cs +++ b/RDMSharp/RDM/PayloadObject/RDMOutputResponseTime.cs @@ -1,13 +1,17 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.OUTPUT_RESPONSE_TIME, Command.ECommandDublicte.GetResponse)] public class RDMOutputResponseTime : AbstractRDMPayloadObjectOneOf - { + { + [DataTreeObjectConstructor] public RDMOutputResponseTime( - byte currentResponseTimeId = 1, - byte responseTimes = 0) + [DataTreeObjectParameter("setting")] byte currentResponseTimeId = 1, + [DataTreeObjectParameter("setting_count")] byte responseTimes = 0) { this.CurrentResponseTimeId = currentResponseTimeId; this.ResponseTimes = responseTimes; diff --git a/RDMSharp/RDM/PayloadObject/RDMOutputResponseTimeDescription.cs b/RDMSharp/RDM/PayloadObject/RDMOutputResponseTimeDescription.cs index 1075ab1..d034517 100644 --- a/RDMSharp/RDM/PayloadObject/RDMOutputResponseTimeDescription.cs +++ b/RDMSharp/RDM/PayloadObject/RDMOutputResponseTimeDescription.cs @@ -1,12 +1,16 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.OUTPUT_RESPONSE_TIME_DESCRIPTION, Command.ECommandDublicte.GetResponse)] public class RDMOutputResponseTimeDescription : AbstractRDMPayloadObject, IRDMPayloadObjectIndex - { + { + [DataTreeObjectConstructor] public RDMOutputResponseTimeDescription( - byte outputResponseTimeId = 1, - string description = "") + [DataTreeObjectParameter("setting")] byte outputResponseTimeId = 1, + [DataTreeObjectParameter("description")] string description = "") { this.OutputResponseTimeId = outputResponseTimeId; diff --git a/RDMSharp/RDM/PayloadObject/RDMParameterDescription.cs b/RDMSharp/RDM/PayloadObject/RDMParameterDescription.cs index 40bcb57..ebdd036 100644 --- a/RDMSharp/RDM/PayloadObject/RDMParameterDescription.cs +++ b/RDMSharp/RDM/PayloadObject/RDMParameterDescription.cs @@ -1,8 +1,11 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.PARAMETER_DESCRIPTION, Command.ECommandDublicte.GetResponse)] public class RDMParameterDescription : AbstractRDMPayloadObject { [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060")] @@ -37,6 +40,22 @@ public RDMParameterDescription( this.Description = description; } + [DataTreeObjectConstructor] + public RDMParameterDescription( + [DataTreeObjectParameter("pid")] ushort parameterId, + [DataTreeObjectParameter("pdl")] byte pdlSize, + [DataTreeObjectParameter("data_type")] byte dataType, + [DataTreeObjectParameter("command_class")] byte commandClass, + [DataTreeObjectParameter("type")] byte type, //Obsolete + [DataTreeObjectParameter("unit")] byte unit, + [DataTreeObjectParameter("unit_prefix")] byte prefix, + [DataTreeObjectParameter("min_valid_value")] int minValidValue, + [DataTreeObjectParameter("max_valid_value")] int maxValidValue, + [DataTreeObjectParameter("default_value")] int defaultValue, + [DataTreeObjectParameter("description")] string description) + : this(parameterId, pdlSize, (ERDM_DataType)dataType, (ERDM_CommandClass)commandClass, type, (ERDM_SensorUnit)unit, (ERDM_UnitPrefix)prefix, minValidValue, maxValidValue, defaultValue, description) + { + } public ushort ParameterId { get; private set; } public byte PDLSize { get; private set; } diff --git a/RDMSharp/RDM/PayloadObject/RDMPersonalityId.cs b/RDMSharp/RDM/PayloadObject/RDMPersonalityId.cs index 167fe06..3457f99 100644 --- a/RDMSharp/RDM/PayloadObject/RDMPersonalityId.cs +++ b/RDMSharp/RDM/PayloadObject/RDMPersonalityId.cs @@ -1,15 +1,18 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.DMX_PERSONALITY_ID, Command.ECommandDublicte.GetResponse)] public class RDMPersonalityId : AbstractRDMPayloadObject, IRDMPayloadObjectIndex { + [DataTreeObjectConstructor] public RDMPersonalityId( - byte personalityId = 0, - ushort majorPersonalityId = 0, - ushort minorPersonalityId = 0) + [DataTreeObjectParameter("personality")] byte personalityId = 0, + [DataTreeObjectParameter("major_id")] ushort majorPersonalityId = 0, + [DataTreeObjectParameter("minor_id")] ushort minorPersonalityId = 0) { this.PersonalityId = personalityId; this.MinorPersonalityId = majorPersonalityId; diff --git a/RDMSharp/RDM/PayloadObject/RDMPresetInfo.cs b/RDMSharp/RDM/PayloadObject/RDMPresetInfo.cs index 087910c..8c210ff 100644 --- a/RDMSharp/RDM/PayloadObject/RDMPresetInfo.cs +++ b/RDMSharp/RDM/PayloadObject/RDMPresetInfo.cs @@ -1,30 +1,34 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.PRESET_INFO, Command.ECommandDublicte.GetResponse)] public class RDMPresetInfo : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public RDMPresetInfo( - bool levelFieldSupported = false, - bool presetSequenceSupported = false, - bool splitTimesSupported = false, - bool dmx512FailInfiniteDelayTimeSupported = false, - bool dmx512FailInfiniteHoldTimeSupported = false, - bool startupInfiniteHoldTimeSupported = false, - ushort maximumSceneNumber = 0, - ushort minimumPresetFadeTimeSupported = 0, - ushort maximumPresetFadeTimeSupported = 0, - ushort minimumPresetWaitTimeSupported = 0, - ushort maximumPresetWaitTimeSupported = 0, - ushort? minimumDMX512FailDelayTimeSupported = null, - ushort? maximumDMX512FailDelayTimeSupported = null, - ushort? minimumDMX512FailDelayHoldSupported = null, - ushort? maximumDMX512FailDelayHoldSupported = null, - ushort? minimumStartupDelayTimeSupported = null, - ushort? maximumStartupDelayTimeSupported = null, - ushort? minimumStartupDelayHoldSupported = null, - ushort? maximumStartupDelayHoldSupported = null) + [DataTreeObjectParameter("level_field_supported")] bool levelFieldSupported = false, + [DataTreeObjectParameter("preset_sequence_supported")] bool presetSequenceSupported = false, + [DataTreeObjectParameter("split_times_supported")] bool splitTimesSupported = false, + [DataTreeObjectParameter("dmx_fail_infinite_delay_time_supported")] bool dmx512FailInfiniteDelayTimeSupported = false, + [DataTreeObjectParameter("dmx_fail_infinite_hold_time_supported")] bool dmx512FailInfiniteHoldTimeSupported = false, + [DataTreeObjectParameter("startup_infinite_hold_time_supported")] bool startupInfiniteHoldTimeSupported = false, + [DataTreeObjectParameter("max_scene_number")] ushort maximumSceneNumber = 0, + [DataTreeObjectParameter("preset_min_fade_time")] ushort minimumPresetFadeTimeSupported = 0, + [DataTreeObjectParameter("preset_max_fade_time")] ushort maximumPresetFadeTimeSupported = 0, + [DataTreeObjectParameter("preset_min_wait_time")] ushort minimumPresetWaitTimeSupported = 0, + [DataTreeObjectParameter("preset_max_wait_time")] ushort maximumPresetWaitTimeSupported = 0, + [DataTreeObjectParameter("dmx_fail_min_delay_time")] ushort? minimumDMX512FailDelayTimeSupported = null, + [DataTreeObjectParameter("dmx_fail_max_delay_time")] ushort? maximumDMX512FailDelayTimeSupported = null, + [DataTreeObjectParameter("dmx_fail_min_hold_time")] ushort? minimumDMX512FailDelayHoldSupported = null, + [DataTreeObjectParameter("dmx_fail_max_hold_time")] ushort? maximumDMX512FailDelayHoldSupported = null, + [DataTreeObjectParameter("startup_min_delay_time")] ushort? minimumStartupDelayTimeSupported = null, + [DataTreeObjectParameter("startup_max_delay_time")] ushort? maximumStartupDelayTimeSupported = null, + [DataTreeObjectParameter("startup_min_hold_time")] ushort? minimumStartupDelayHoldSupported = null, + [DataTreeObjectParameter("startup_max_hold_time")] ushort? maximumStartupDelayHoldSupported = null) { this.LevelFieldSupported = levelFieldSupported; this.PresetSequenceSupported = presetSequenceSupported; diff --git a/RDMSharp/RDM/PayloadObject/RDMPresetPlayback.cs b/RDMSharp/RDM/PayloadObject/RDMPresetPlayback.cs index c5fbbca..51095a9 100644 --- a/RDMSharp/RDM/PayloadObject/RDMPresetPlayback.cs +++ b/RDMSharp/RDM/PayloadObject/RDMPresetPlayback.cs @@ -1,13 +1,18 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.PRESET_PLAYBACK, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.PRESET_PLAYBACK, Command.ECommandDublicte.SetRequest)] public class RDMPresetPlayback : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public RDMPresetPlayback( - ushort mode = 0, - byte level = 0) + [DataTreeObjectParameter("mode")] ushort mode = 0, + [DataTreeObjectParameter("level")] byte level = 0) { this.Mode = mode; this.Level = level; diff --git a/RDMSharp/RDM/PayloadObject/RDMPresetStatus.cs b/RDMSharp/RDM/PayloadObject/RDMPresetStatus.cs index bd75149..a373d94 100644 --- a/RDMSharp/RDM/PayloadObject/RDMPresetStatus.cs +++ b/RDMSharp/RDM/PayloadObject/RDMPresetStatus.cs @@ -1,8 +1,13 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.PRESET_STATUS, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.PRESET_STATUS, Command.ECommandDublicte.SetRequest)] + [DataTreeObject(ERDM_Parameter.CAPTURE_PRESET, Command.ECommandDublicte.SetRequest)] public class RDMPresetStatus : AbstractRDMPayloadObject { public RDMPresetStatus( @@ -19,6 +24,17 @@ public RDMPresetStatus( this.Programmed = programmed; } + [DataTreeObjectConstructor] + public RDMPresetStatus( + [DataTreeObjectParameter("scene_num")] ushort sceneId, + [DataTreeObjectParameter("up_fade_time")] ushort upFadeTime, + [DataTreeObjectParameter("down_fade_time")] ushort downFadeTime, + [DataTreeObjectParameter("wait_time")] ushort waitTime, + [DataTreeObjectParameter("programmed")] byte programmed) + : this(sceneId, upFadeTime, downFadeTime, waitTime, (ERDM_PresetProgrammed)programmed) + { + } + public ushort SceneId { get; private set; } /// /// Tenths of a second diff --git a/RDMSharp/RDM/PayloadObject/RDMProxiedDeviceCount.cs b/RDMSharp/RDM/PayloadObject/RDMProxiedDeviceCount.cs index cf5537f..c9b7665 100644 --- a/RDMSharp/RDM/PayloadObject/RDMProxiedDeviceCount.cs +++ b/RDMSharp/RDM/PayloadObject/RDMProxiedDeviceCount.cs @@ -1,13 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.PROXIED_DEVICES_COUNT, Command.ECommandDublicte.GetResponse)] public class RDMProxiedDeviceCount : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public RDMProxiedDeviceCount( - ushort deviceCount = 0, - bool listChange = false) + [DataTreeObjectParameter("device_count")] ushort deviceCount = 0, + [DataTreeObjectParameter("list_change")] bool listChange = false) { this.DeviceCount = deviceCount; this.ListChange = listChange; diff --git a/RDMSharp/RDM/PayloadObject/RDMProxiedDevices.cs b/RDMSharp/RDM/PayloadObject/RDMProxiedDevices.cs index 7a48484..b78be32 100644 --- a/RDMSharp/RDM/PayloadObject/RDMProxiedDevices.cs +++ b/RDMSharp/RDM/PayloadObject/RDMProxiedDevices.cs @@ -1,12 +1,16 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; using System.Text; namespace RDMSharp { + //[DataTreeObject(ERDM_Parameter.PROXIED_DEVICES, Command.ECommandDublicte.GetResponse, path: "device_uids")] Dont use this because its an Arrya and this is handled faster public class RDMProxiedDevices : AbstractRDMPayloadObject { - public RDMProxiedDevices(params UID[] devices) + [DataTreeObjectConstructor] + public RDMProxiedDevices(/*[DataTreeObjectParameter("device_uid", true)]*/ params UID[] devices) { this.Devices = devices; } diff --git a/RDMSharp/RDM/PayloadObject/RDMRealTimeClock.cs b/RDMSharp/RDM/PayloadObject/RDMRealTimeClock.cs index 80c3963..0161580 100644 --- a/RDMSharp/RDM/PayloadObject/RDMRealTimeClock.cs +++ b/RDMSharp/RDM/PayloadObject/RDMRealTimeClock.cs @@ -1,17 +1,22 @@ -using System; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System; using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.REAL_TIME_CLOCK, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.REAL_TIME_CLOCK, Command.ECommandDublicte.SetRequest)] public class RDMRealTimeClock : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public RDMRealTimeClock( - ushort year = 2003, - byte month = 1, - byte day = 1, - byte hour = 0, - byte minute = 0, - byte second = 0) + [DataTreeObjectParameter("year")] ushort year = 2003, + [DataTreeObjectParameter("month")] byte month = 1, + [DataTreeObjectParameter("day")] byte day = 1, + [DataTreeObjectParameter("hour")] byte hour = 0, + [DataTreeObjectParameter("minute")] byte minute = 0, + [DataTreeObjectParameter("second")] byte second = 0) { if (year < 2003) throw new ArgumentOutOfRangeException($"{nameof(year)} shold be a value between 2003 and 65535 but is {year}"); diff --git a/RDMSharp/RDM/PayloadObject/RDMSelfTestDescription.cs b/RDMSharp/RDM/PayloadObject/RDMSelfTestDescription.cs index 7a18323..5882723 100644 --- a/RDMSharp/RDM/PayloadObject/RDMSelfTestDescription.cs +++ b/RDMSharp/RDM/PayloadObject/RDMSelfTestDescription.cs @@ -1,13 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.SELF_TEST_DESCRIPTION, Command.ECommandDublicte.GetResponse)] public class RDMSelfTestDescription : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public RDMSelfTestDescription( - byte selfTestRequester = 0, - string description = "") + [DataTreeObjectParameter("self_test_num")] byte selfTestRequester = 0, + [DataTreeObjectParameter("label")] string description = "") { this.SelfTestRequester = selfTestRequester; diff --git a/RDMSharp/RDM/PayloadObject/RDMSensorDefinition.cs b/RDMSharp/RDM/PayloadObject/RDMSensorDefinition.cs index ac43653..c5a0fd3 100644 --- a/RDMSharp/RDM/PayloadObject/RDMSensorDefinition.cs +++ b/RDMSharp/RDM/PayloadObject/RDMSensorDefinition.cs @@ -1,8 +1,11 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.SENSOR_DEFINITION, Command.ECommandDublicte.GetResponse)] public class RDMSensorDefinition : AbstractRDMPayloadObject, IRDMPayloadObjectIndex { public RDMSensorDefinition( @@ -36,18 +39,56 @@ public RDMSensorDefinition( description = description.Substring(0, 32); this.Description = description; - } - - public byte SensorId { get; private set; } - public ERDM_SensorType Type { get; private set; } - public ERDM_SensorUnit Unit { get; private set; } - public ERDM_UnitPrefix Prefix { get; private set; } - public short RangeMinimum { get; private set; } - public short RangeMaximum { get; private set; } - public short NormalMinimum { get; private set; } - public short NormalMaximum { get; private set; } - public bool LowestHighestValueSupported { get; private set; } - public bool RecordedValueSupported { get; private set; } + } + + [DataTreeObjectConstructor] + public RDMSensorDefinition( + [DataTreeObjectParameter("sensor")] byte sensorId, + [DataTreeObjectParameter("type")] byte type, + [DataTreeObjectParameter("unit")] byte unit, + [DataTreeObjectParameter("unit_prefix")] byte prefix, + [DataTreeObjectParameter("range_min_value")] short rangeMinimum, + [DataTreeObjectParameter("range_max_value")] short rangeMaximum, + [DataTreeObjectParameter("normal_min_value")] short normalMinimum, + [DataTreeObjectParameter("normal_max_value")] short normalMaximum, + [DataTreeObjectParameter("recorded_value_support/recorded_value_supported")] bool recordedValueSupported, + [DataTreeObjectParameter("recorded_value_support/low_high_detected_values_supported")] bool lowestHighestValueSupported, + [DataTreeObjectParameter("description")] string description) + : this(sensorId, + (ERDM_SensorType)type, + (ERDM_SensorUnit)unit, + (ERDM_UnitPrefix)prefix, + rangeMinimum, + rangeMaximum, + normalMinimum, + normalMaximum, + lowestHighestValueSupported, + recordedValueSupported, + description) + { + } + + [DataTreeObjectProperty("sensor", 0)] + public byte SensorId { get; private set; } + [DataTreeObjectProperty("type", 1)] + public ERDM_SensorType Type { get; private set; } + [DataTreeObjectProperty("unit", 2)] + public ERDM_SensorUnit Unit { get; private set; } + [DataTreeObjectProperty("unit_prefix", 3)] + public ERDM_UnitPrefix Prefix { get; private set; } + [DataTreeObjectProperty("range_min_value", 4)] + public short RangeMinimum { get; private set; } + [DataTreeObjectProperty("range_max_value", 5)] + public short RangeMaximum { get; private set; } + [DataTreeObjectProperty("normal_min_value", 6)] + public short NormalMinimum { get; private set; } + [DataTreeObjectProperty("normal_max_value", 7)] + public short NormalMaximum { get; private set; } + [DataTreeObjectProperty("recorded_value_support/recorded_value_supported", 0)] + public bool LowestHighestValueSupported { get; private set; } + [DataTreeObjectProperty("recorded_value_support/low_high_detected_values_supported", 1)] + public bool RecordedValueSupported { get; private set; } + [DataTreeObjectProperty("description", 9)] public string Description { get; private set; } public object MinIndex => (byte)0; diff --git a/RDMSharp/RDM/PayloadObject/RDMSensorTypeCustomDefine.cs b/RDMSharp/RDM/PayloadObject/RDMSensorTypeCustomDefine.cs index cbb7aa4..b17a775 100644 --- a/RDMSharp/RDM/PayloadObject/RDMSensorTypeCustomDefine.cs +++ b/RDMSharp/RDM/PayloadObject/RDMSensorTypeCustomDefine.cs @@ -1,13 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.SENSOR_TYPE_CUSTOM, Command.ECommandDublicte.GetResponse)] public class RDMSensorTypeCustomDefine : AbstractRDMPayloadObject, IRDMPayloadObjectIndex { + [DataTreeObjectConstructor] public RDMSensorTypeCustomDefine( - byte id, - string label) + [DataTreeObjectParameter("sensor_type")] byte id, + [DataTreeObjectParameter("label")] string label) { this.Id = id; this.Label = label; diff --git a/RDMSharp/RDM/PayloadObject/RDMSensorUnitCustomDefine.cs b/RDMSharp/RDM/PayloadObject/RDMSensorUnitCustomDefine.cs index b4ccd48..6a628e3 100644 --- a/RDMSharp/RDM/PayloadObject/RDMSensorUnitCustomDefine.cs +++ b/RDMSharp/RDM/PayloadObject/RDMSensorUnitCustomDefine.cs @@ -1,13 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.SENSOR_UNIT_CUSTOM, Command.ECommandDublicte.GetResponse)] public class RDMSensorUnitCustomDefine : AbstractRDMPayloadObject, IRDMPayloadObjectIndex { + [DataTreeObjectConstructor] public RDMSensorUnitCustomDefine( - byte id, - string label) + [DataTreeObjectParameter("sensor_unit")] byte id, + [DataTreeObjectParameter("label")] string label) { this.Id = id; this.Label = label; diff --git a/RDMSharp/RDM/PayloadObject/RDMSensorValue.cs b/RDMSharp/RDM/PayloadObject/RDMSensorValue.cs index 473a7f9..b115545 100644 --- a/RDMSharp/RDM/PayloadObject/RDMSensorValue.cs +++ b/RDMSharp/RDM/PayloadObject/RDMSensorValue.cs @@ -1,16 +1,21 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.SENSOR_VALUE, Command.ECommandDublicte.GetResponse)] + [DataTreeObject(ERDM_Parameter.SENSOR_VALUE, Command.ECommandDublicte.SetResponse)] public class RDMSensorValue : AbstractRDMPayloadObject, IRDMPayloadObjectIndex - { + { + [DataTreeObjectConstructor] public RDMSensorValue( - byte sensorId = 0, - short presentvalue = 0, - short lowestValue = 0, - short highestValue = 0, - short recordedValue = 0) + [DataTreeObjectParameter("sensor")] byte sensorId = 0, + [DataTreeObjectParameter("value")] short presentvalue = 0, + [DataTreeObjectParameter("lowest_detected")] short lowestValue = 0, + [DataTreeObjectParameter("highest_detected")] short highestValue = 0, + [DataTreeObjectParameter("recorded_value")] short recordedValue = 0) { this.SensorId = sensorId; this.PresentValue = presentvalue; @@ -19,10 +24,19 @@ public RDMSensorValue( this.RecordedValue = recordedValue; } + [DataTreeObjectProperty("sensor", 0)] public byte SensorId { get; private set; } + + [DataTreeObjectProperty("value", 1)] public short PresentValue { get; private set; } + + [DataTreeObjectProperty("lowest_detected", 2)] public short LowestValue { get; private set; } + + [DataTreeObjectProperty("highest_detected", 3)] public short HighestValue { get; private set; } + + [DataTreeObjectProperty("recorded_value", 4)] public short RecordedValue { get; private set; } public object MinIndex => (byte)0; diff --git a/RDMSharp/RDM/PayloadObject/RDMSlotDescription.cs b/RDMSharp/RDM/PayloadObject/RDMSlotDescription.cs index 400da5a..0af3634 100644 --- a/RDMSharp/RDM/PayloadObject/RDMSlotDescription.cs +++ b/RDMSharp/RDM/PayloadObject/RDMSlotDescription.cs @@ -1,12 +1,16 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.SLOT_DESCRIPTION, Command.ECommandDublicte.GetResponse)] public class RDMSlotDescription : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public RDMSlotDescription( - ushort slotId = 0, - string description = "") + [DataTreeObjectParameter("slot")] ushort slotId = 0, + [DataTreeObjectParameter("description")] string description = "") { this.SlotId = slotId; @@ -19,8 +23,12 @@ public RDMSlotDescription( this.Description = description; } + [DataTreeObjectProperty("slot", 0)] public ushort SlotId { get; private set; } + + [DataTreeObjectProperty("description", 1)] public string Description { get; private set; } + public const int PDL_MIN = 2; public const int PDL_MAX = PDL_MIN + 32; diff --git a/RDMSharp/RDM/PayloadObject/RDMSlotInfo.cs b/RDMSharp/RDM/PayloadObject/RDMSlotInfo.cs index 51797b4..2c9771c 100644 --- a/RDMSharp/RDM/PayloadObject/RDMSlotInfo.cs +++ b/RDMSharp/RDM/PayloadObject/RDMSlotInfo.cs @@ -1,8 +1,11 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.SLOT_INFO, Command.ECommandDublicte.GetResponse, true, "slots")] public class RDMSlotInfo : AbstractRDMPayloadObject { public RDMSlotInfo( @@ -15,8 +18,22 @@ public RDMSlotInfo( this.SlotLabelId = slotLabelId; } + [DataTreeObjectConstructor] + public RDMSlotInfo( + [DataTreeObjectParameter("id")] ushort slotOffset, + [DataTreeObjectParameter("type")] byte slotType, + [DataTreeObjectParameter("label_id")] ushort slotLabelId) + : this(slotOffset, (ERDM_SlotType)slotType, (ERDM_SlotCategory)slotLabelId) + { + } + + [DataTreeObjectProperty("id", 0)] public ushort SlotOffset { get; private set; } + + [DataTreeObjectProperty("type", 1)] public ERDM_SlotType SlotType { get; private set; } + + [DataTreeObjectProperty("label_id", 2)] public ERDM_SlotCategory SlotLabelId { get; private set; } public const int PDL = 5; diff --git a/RDMSharp/RDM/PayloadObject/RDMStatusMessage.cs b/RDMSharp/RDM/PayloadObject/RDMStatusMessage.cs index dfa997d..185bf9a 100644 --- a/RDMSharp/RDM/PayloadObject/RDMStatusMessage.cs +++ b/RDMSharp/RDM/PayloadObject/RDMStatusMessage.cs @@ -1,8 +1,11 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Text; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.STATUS_MESSAGES, Command.ECommandDublicte.GetResponse, true, "slots")] public class RDMStatusMessage : AbstractRDMPayloadObject { public RDMStatusMessage( @@ -19,6 +22,17 @@ public RDMStatusMessage( this.DataValue2 = dataValue2; } + [DataTreeObjectConstructor] + public RDMStatusMessage( + [DataTreeObjectParameter("slots/subdevice_id")] ushort subDeviceId, + [DataTreeObjectParameter("slots/status_type")] byte statusType, + [DataTreeObjectParameter("slots/status_message_id")] byte statusMessage, + [DataTreeObjectParameter("slots/data_value_1")] short dataValue1, + [DataTreeObjectParameter("slots/data_value_2")] short dataValue2) + : this(subDeviceId, (ERDM_Status)statusType, (ERDM_StatusMessage)statusMessage, dataValue1, dataValue2) + { + } + public ushort SubDeviceId { get; private set; } public ERDM_Status StatusType { get; private set; } diff --git a/RDMSharp/RDM/PayloadObject/SetDiscoveryStateRequest.cs b/RDMSharp/RDM/PayloadObject/SetDiscoveryStateRequest.cs index afc7c26..9f92081 100644 --- a/RDMSharp/RDM/PayloadObject/SetDiscoveryStateRequest.cs +++ b/RDMSharp/RDM/PayloadObject/SetDiscoveryStateRequest.cs @@ -1,16 +1,26 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.DISCOVERY_STATE, Command.ECommandDublicte.SetResponse)] public class SetDiscoveryStateRequest : AbstractRDMPayloadObject { public SetDiscoveryStateRequest( - ushort endpointId = default, - ERDM_DiscoveryState discoveryState = default) + [DataTreeObjectParameter("endpoint_id")] ushort endpointId = default, + [DataTreeObjectParameter("state")] ERDM_DiscoveryState discoveryState = default) { this.EndpointId = endpointId; this.DiscoveryState = discoveryState; } + [DataTreeObjectConstructor] + public SetDiscoveryStateRequest( + [DataTreeObjectParameter("endpoint_id")] ushort endpointId, + [DataTreeObjectParameter("state")] byte discoveryState) + : this(endpointId, (ERDM_DiscoveryState)discoveryState) + { + } public ushort EndpointId { get; private set; } public ERDM_DiscoveryState DiscoveryState { get; private set; } diff --git a/RDMSharp/RDM/PayloadObject/SetEndpointTimingRequest.cs b/RDMSharp/RDM/PayloadObject/SetEndpointTimingRequest.cs index e8342b7..8b3130c 100644 --- a/RDMSharp/RDM/PayloadObject/SetEndpointTimingRequest.cs +++ b/RDMSharp/RDM/PayloadObject/SetEndpointTimingRequest.cs @@ -1,12 +1,17 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.ENDPOINT_TIMING, Command.ECommandDublicte.SetRequest)] + public class SetEndpointTimingRequest : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public SetEndpointTimingRequest( - ushort endpointId = default, - byte timingId = default) + [DataTreeObjectParameter("endpoint_id")] ushort endpointId = default, + [DataTreeObjectParameter("setting")] byte timingId = default) { this.EndpointId = endpointId; this.TimingId = timingId; diff --git a/RDMSharp/RDM/PayloadObject/SetLockPinRequest.cs b/RDMSharp/RDM/PayloadObject/SetLockPinRequest.cs index 28eb461..62304f9 100644 --- a/RDMSharp/RDM/PayloadObject/SetLockPinRequest.cs +++ b/RDMSharp/RDM/PayloadObject/SetLockPinRequest.cs @@ -1,12 +1,16 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.LOCK_PIN, Command.ECommandDublicte.SetRequest)] public class SetLockPinRequest : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public SetLockPinRequest( - ushort newPinCode = 0, - ushort currentPinCode = 0) + [DataTreeObjectParameter("new_pin_code")] ushort newPinCode = 0, + [DataTreeObjectParameter("current_pin_code")] ushort currentPinCode = 0) { this.NewPinCode = newPinCode; this.CurrentPinCode = currentPinCode; diff --git a/RDMSharp/RDM/PayloadObject/SetLockStateRequest.cs b/RDMSharp/RDM/PayloadObject/SetLockStateRequest.cs index 91acbf6..c814540 100644 --- a/RDMSharp/RDM/PayloadObject/SetLockStateRequest.cs +++ b/RDMSharp/RDM/PayloadObject/SetLockStateRequest.cs @@ -1,12 +1,16 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; namespace RDMSharp { + [DataTreeObject(ERDM_Parameter.LOCK_STATE, Command.ECommandDublicte.SetRequest)] public class SetLockStateRequest : AbstractRDMPayloadObject { + [DataTreeObjectConstructor] public SetLockStateRequest( - ushort pinCode = 0, - byte lockStateId = 0) + [DataTreeObjectParameter("pin_code")] ushort pinCode = 0, + [DataTreeObjectParameter("state")] byte lockStateId = 0) { this.PinCode = pinCode; this.LockStateId = lockStateId; diff --git a/RDMSharp/RDM/PayloadObject/TCPCommsEntry.cs b/RDMSharp/RDM/PayloadObject/TCPCommsEntry.cs index 7926668..7582513 100644 --- a/RDMSharp/RDM/PayloadObject/TCPCommsEntry.cs +++ b/RDMSharp/RDM/PayloadObject/TCPCommsEntry.cs @@ -1,18 +1,22 @@ -using System.Collections.Generic; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; namespace RDMSharp -{ +{ + [DataTreeObject(ERDM_Parameter.TCP_COMMS_STATUS, Command.ECommandDublicte.GetResponse)] public class TCPCommsEntry : AbstractRDMPayloadObject - { + { + [DataTreeObjectConstructor] public TCPCommsEntry( - string scopeString = default, - IPAddress brokerAddress = default, - ushort brokerPort = default, - ushort unhealthyTCPEvents = default) + [DataTreeObjectParameter("scopeString")] string scopeString = default, + [DataTreeObjectParameter("brokerAddress")] IPAddress brokerAddress = default, + [DataTreeObjectParameter("brokerPort")] ushort brokerPort = default, + [DataTreeObjectParameter("unhealthyTCPEvents")] ushort unhealthyTCPEvents = default) { if (string.IsNullOrWhiteSpace(scopeString)) diff --git a/RDMSharp/RDM/PeerToPeerProcess.cs b/RDMSharp/RDM/PeerToPeerProcess.cs new file mode 100644 index 0000000..b29e6b8 --- /dev/null +++ b/RDMSharp/RDM/PeerToPeerProcess.cs @@ -0,0 +1,120 @@ +using RDMSharp.Metadata; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using static RDMSharp.Metadata.JSON.Command; + +namespace RDMSharp +{ + public class PeerToPeerProcess + { + public enum EPeerToPeerProcessState + { + Waiting, + Running, + Finished, + Failed + } + public readonly ERDM_Command Command; + public readonly UID UID; + public readonly SubDevice SubDevice; + public readonly ParameterBag ParameterBag; + public readonly DataTreeBranch RequestPayloadObject; + public DataTreeBranch ResponsePayloadObject { get; private set; } = DataTreeBranch.Unset; + + public MetadataJSONObjectDefine Define { get; private set; } + public EPeerToPeerProcessState State { get; private set; } = EPeerToPeerProcessState.Waiting; + + public Exception Exception { get; private set; } + + private RDMMessage request = null; + private RDMMessage response = null; + public PeerToPeerProcess(ERDM_Command command, UID uid, SubDevice subDevice, ParameterBag parameterBag, DataTreeBranch? payloadObject = null) + { + if (command != ERDM_Command.GET_COMMAND) + if (command != ERDM_Command.SET_COMMAND) + throw new ArgumentException($"{nameof(command)} should be {ERDM_Command.GET_COMMAND} or {ERDM_Command.SET_COMMAND}"); + + Command = command; + UID = uid; + SubDevice = subDevice; + ParameterBag = parameterBag; + RequestPayloadObject = payloadObject ?? DataTreeBranch.Unset; + + Define = MetadataFactory.GetDefine(ParameterBag); + } + + public async Task Run(AsyncRDMRequestHelper asyncRDMRequestHelper) + { + await run(asyncRDMRequestHelper); + } + + private async Task run(AsyncRDMRequestHelper asyncRDMRequestHelper) + { + try + { + if (State != EPeerToPeerProcessState.Waiting) + return; + + if (asyncRDMRequestHelper == null) + throw new ArgumentNullException(nameof(asyncRDMRequestHelper)); + + State = EPeerToPeerProcessState.Running; + + ECommandDublicte commandRequest = ECommandDublicte.GetRequest; + if (Command == ERDM_Command.SET_COMMAND) + commandRequest = ECommandDublicte.SetRequest; + + ECommandDublicte commandResponse = ECommandDublicte.GetResponse; + if (Command == ERDM_Command.SET_COMMAND) + commandResponse = ECommandDublicte.SetResponse; + + byte[] parameterData = MetadataFactory.ParsePayloadToData(Define, commandRequest, RequestPayloadObject); + request = new RDMMessage() + { + Command = Command, + DestUID = UID, + SubDevice = SubDevice, + Parameter = ParameterBag.PID, + ParameterData = parameterData + }; + List bytes = new List(); + while (State == EPeerToPeerProcessState.Running) + { + var responseResult = await asyncRDMRequestHelper.RequestMessage(request); + if (!responseResult.Success) + { + State = EPeerToPeerProcessState.Failed; + return; + } + response = responseResult.Response; + if (response.ResponseType == ERDM_ResponseType.ACK_TIMER && response.Value is AcknowledgeTimer timer) + { + await Task.Delay(timer.EstimidatedResponseTime); + request.Parameter = ERDM_Parameter.QUEUED_MESSAGE; + //Send Message on next loop + continue; + } + bytes.AddRange(response.ParameterData); + if (response.ResponseType == ERDM_ResponseType.ACK) + { + ResponsePayloadObject = MetadataFactory.ParseDataToPayload(Define, commandResponse, bytes.ToArray()); + State = EPeerToPeerProcessState.Finished; + return; + } + if (response.ResponseType == ERDM_ResponseType.ACK_OVERFLOW) + { + //Do nothing else send another Request + //Send Message on next loop + continue; + } + } + } + catch (Exception e) + { + this.Exception = e; + State = EPeerToPeerProcessState.Failed; + } + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/RDMMessage.cs b/RDMSharp/RDM/RDMMessage.cs index cc6b628..568f6db 100644 --- a/RDMSharp/RDM/RDMMessage.cs +++ b/RDMSharp/RDM/RDMMessage.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Logging; +using RDMSharp.Metadata; using RDMSharp.ParameterWrapper; using System; using System.Collections.Generic; @@ -121,9 +122,24 @@ public byte MessageLength public UID DestUID { get; set; } - public byte TransactionCounter { get; set; } - - public byte PortID_or_Responsetype { get; set; } + public byte TransactionCounter { get; set; } + + private byte portID_or_Responsetype; + public byte PortID_or_Responsetype { + get + { + return portID_or_Responsetype; + } + set + { + if (value == portID_or_Responsetype) + return; + + valueCache = null; + + portID_or_Responsetype = value; + } + } public byte MessageCounter { get; set; } public byte? PreambleCount @@ -153,11 +169,39 @@ public byte? PreambleCount } } - public SubDevice SubDevice { get; set; } - - public ERDM_Command Command { get; set; } - - public ERDM_Parameter Parameter { get; set; } + public SubDevice SubDevice { get; set; } + + private ERDM_Command command; + public ERDM_Command Command + { + get + { + return command; + } + set + { + if (value == command) + return; + valueCache = null; + command = value; + } + } + + private ERDM_Parameter parameter; + public ERDM_Parameter Parameter + { + get + { + return parameter; + } + set + { + if (value == parameter) + return; + valueCache = null; + parameter = value; + } + } private ERDM_NackReason[] nackReason = null; @@ -193,6 +237,11 @@ public byte[] ParameterData get { return _parameterData; } set { + if (_parameterData == value) + return; + + valueCache = null; + if (value == null) _parameterData = Array.Empty(); else @@ -330,6 +379,7 @@ public byte[] BuildMessage() } } + private object valueCache = null; public object Value { get @@ -337,20 +387,43 @@ public object Value try { if (this.ResponseType == ERDM_ResponseType.ACK_TIMER) - return AcknowledgeTimer.FromPayloadData(this.ParameterData); + return valueCache = AcknowledgeTimer.FromPayloadData(this.ParameterData); if (this.Parameter == ERDM_Parameter.DISC_UNIQUE_BRANCH && this.Command == ERDM_Command.DISCOVERY_COMMAND) - return DiscUniqueBranchRequest.FromPayloadData(this.ParameterData); + return valueCache = DiscUniqueBranchRequest.FromPayloadData(this.ParameterData); if (this.Parameter == ERDM_Parameter.DISC_MUTE && this.Command == ERDM_Command.DISCOVERY_COMMAND_RESPONSE) - return DiscMuteUnmuteResponse.FromPayloadData(this.ParameterData); + return valueCache = DiscMuteUnmuteResponse.FromPayloadData(this.ParameterData); if (this.Parameter == ERDM_Parameter.DISC_UN_MUTE && this.Command == ERDM_Command.DISCOVERY_COMMAND_RESPONSE) - return DiscMuteUnmuteResponse.FromPayloadData(this.ParameterData); + return valueCache = DiscMuteUnmuteResponse.FromPayloadData(this.ParameterData); - return RDMParameterWrapperCatalogueManager.GetInstance().ParameterDataObjectFromMessage(this); + if (this.ParameterData?.Length == 0) + return valueCache = null; + + try + { + ushort manufacturer = 0; + if (this.Command.HasFlag(ERDM_Command.RESPONSE)) + { + manufacturer = SourceUID.ManufacturerID; + } + else + { + manufacturer = DestUID.ManufacturerID; + } + + return valueCache = MetadataFactory.ParseDataToPayload(MetadataFactory.GetDefine(new ParameterBag(this.Parameter, manufacturer)), Tools.ConvertCommandDublicteToCommand(Command), this.ParameterData).ParsedObject; + + + } + catch (Exception ex) + { + Logger?.LogError(ex); + throw ex; + } } catch (Exception ex) { Logger?.LogError(ex); - return null; + throw ex; } } } @@ -375,37 +448,21 @@ public override string ToString() Command == ERDM_Command.SET_COMMAND_RESPONSE || Command.HasFlag(ERDM_Command.DISCOVERY_COMMAND)) { - var pm = RDMParameterWrapperCatalogueManager.GetInstance().GetRDMParameterWrapperByID(Parameter); - switch (Command) - { - case ERDM_Command.SET_COMMAND_RESPONSE - when pm is not IRDMSetParameterWrapperWithEmptySetResponse: - b.AppendLine("Value: " + valueString()); - break; - case ERDM_Command.GET_COMMAND_RESPONSE - when pm is not IRDMGetParameterWrapperWithEmptyGetResponse: - b.AppendLine("Value: " + valueString()); - break; - case ERDM_Command.SET_COMMAND - when pm is not IRDMSetParameterWrapperWithEmptySetRequest: - b.AppendLine("Value: " + valueString()); - break; - default: - if (Value != null) - b.AppendLine("Value: " + valueString()); - break; - } + var val = this.Value; + if (val != null) + b.AppendLine("Value: " + valueString()); + string valueString() { string value; - if (Value is Array array) + if (val is Array array) { List list = new List(); foreach (var a in array) list.Add(a.ToString()); value = string.Join("," + Environment.NewLine, list); } - else if (Value is string str) + else if (val is string str) value = $"\"{str}\""; else value = Value?.ToString() ?? "[NULL]"; diff --git a/RDMSharp/RDM/Tools.cs b/RDMSharp/RDM/Tools.cs index 4214ccc..7953df1 100644 --- a/RDMSharp/RDM/Tools.cs +++ b/RDMSharp/RDM/Tools.cs @@ -7,10 +7,54 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using System.Reflection; using System.Text; +using static RDMSharp.Metadata.JSON.Command; namespace RDMSharp { + public static class Constants + { + public static readonly ERDM_Parameter[] BLUEPRINT_MODEL_PARAMETERS = new ERDM_Parameter[] + { + ERDM_Parameter.PARAMETER_DESCRIPTION, + ERDM_Parameter.MANUFACTURER_LABEL, + ERDM_Parameter.MANUFACTURER_URL, + ERDM_Parameter.DEVICE_MODEL_DESCRIPTION, + ERDM_Parameter.PRODUCT_DETAIL_ID_LIST, + ERDM_Parameter.PRODUCT_URL, + ERDM_Parameter.FIRMWARE_URL, + + ERDM_Parameter.METADATA_JSON_URL, + ERDM_Parameter.METADATA_JSON, + ERDM_Parameter.METADATA_PARAMETER_VERSION, + + ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION, + ERDM_Parameter.DMX_PERSONALITY_ID, + + ERDM_Parameter.SENSOR_DEFINITION, + ERDM_Parameter.SENSOR_TYPE_CUSTOM, + ERDM_Parameter.SENSOR_UNIT_CUSTOM, + + ERDM_Parameter.CURVE_DESCRIPTION, + ERDM_Parameter.DIMMER_INFO, + ERDM_Parameter.MODULATION_FREQUENCY_DESCRIPTION, + ERDM_Parameter.OUTPUT_RESPONSE_TIME_DESCRIPTION, + ERDM_Parameter.LOCK_STATE_DESCRIPTION, + + ERDM_Parameter.SELF_TEST_DESCRIPTION, + ERDM_Parameter.STATUS_ID_DESCRIPTION, + ERDM_Parameter.LANGUAGE_CAPABILITIES, + ERDM_Parameter.SOFTWARE_VERSION_LABEL, + }; + + public static readonly ERDM_Parameter[] BLUEPRINT_MODEL_PERSONALITY_PARAMETERS = new ERDM_Parameter[] + { + ERDM_Parameter.SLOT_DESCRIPTION, + ERDM_Parameter.SLOT_INFO, + ERDM_Parameter.DEFAULT_SLOT_VALUE + }; + } public static class Tools { public static int GenerateHashCode(this IEnumerable enumerable) @@ -82,6 +126,13 @@ public static TAttribute GetAttribute(this Enum value) .GetCustomAttributes(false) .OfType() .SingleOrDefault(); + } + public static List FindClassesWithAttribute() where TAttribute : Attribute + { + Assembly assembly = Assembly.GetExecutingAssembly(); + return assembly.GetTypes() + .Where(t => (t.IsClass || t.IsEnum) && t.GetCustomAttributes().Any(a => a is TAttribute)) + .ToList(); } public static byte[] ValueToData(params bool[] bits) @@ -192,8 +243,14 @@ public static byte[] ValueToData(object value, int trim = 32) case long @long: return DoEightByte((ulong)@long); case ulong @ulong: - return DoEightByte(@ulong); - + return DoEightByte(@ulong); +#if NET7_0_OR_GREATER + case Int128 @long: + return DoSixteenByte((UInt128)@long); + case UInt128 @ulong: + return DoSixteenByte(@ulong); +#endif + case string @string: if (trim >= 1) if (@string.Length > trim) @@ -213,18 +270,22 @@ public static byte[] ValueToData(object value, int trim = 32) byte[] DoOneByte(byte b) => new byte[] { b }; byte[] DoTwoByte(ushort s) => new byte[] { (byte)(s >> 8), (byte)s }; byte[] DoFourByte(uint i) => new byte[] { (byte)(i >> 24), (byte)(i >> 16), (byte)(i >> 8), (byte)i }; - byte[] DoEightByte(ulong i) => new byte[] { (byte)(i >> 56), (byte)(i >> 48), (byte)(i >> 40), (byte)(i >> 32), (byte)(i >> 24), (byte)(i >> 16), (byte)(i >> 8), (byte)i }; + byte[] DoEightByte(ulong i) => new byte[] { (byte)(i >> 56), (byte)(i >> 48), (byte)(i >> 40), (byte)(i >> 32), (byte)(i >> 24), (byte)(i >> 16), (byte)(i >> 8), (byte)i }; +#if NET7_0_OR_GREATER + byte[] DoSixteenByte(UInt128 i) => new byte[] { (byte)(i >> 120), (byte)(i >> 112), (byte)(i >> 104), (byte)(i >> 96), (byte)(i >> 88), (byte)(i >> 80), (byte)(i >> 72), (byte)(i >> 64), (byte)(i >> 56), (byte)(i >> 48), (byte)(i >> 40), (byte)(i >> 32), (byte)(i >> 24), (byte)(i >> 16), (byte)(i >> 8), (byte)i }; +#endif } - - public static byte DataToByte(ref byte[] data) + + public static byte DataToByte(ref byte[] data) { const int length = 1; if (data.Length < length) throw new IndexOutOfRangeException(); - byte res = (byte)data[0]; + byte result = (byte)data[0]; + data = data.Skip(length).ToArray(); - return res; + return result; } public static sbyte DataToSByte(ref byte[] data) { @@ -232,9 +293,10 @@ public static sbyte DataToSByte(ref byte[] data) if (data.Length < length) throw new IndexOutOfRangeException(); - sbyte res = (sbyte)data[0]; + sbyte result = (sbyte)data[0]; + data = data.Skip(length).ToArray(); - return res; + return result; } public static short DataToShort(ref byte[] data) { @@ -242,9 +304,10 @@ public static short DataToShort(ref byte[] data) if (data.Length < length) throw new IndexOutOfRangeException(); - short res = (short)((data[0] << 8) | data[1]); + short result = (short)((data[0] << 8) | data[1]); + data = data.Skip(length).ToArray(); - return res; + return result; } public static ushort DataToUShort(ref byte[] data) { @@ -252,9 +315,10 @@ public static ushort DataToUShort(ref byte[] data) if (data.Length < length) throw new IndexOutOfRangeException(); - ushort res = (ushort)((data[0] << 8) | data[1]); + ushort result = (ushort)((data[0] << 8) | data[1]); + data = data.Skip(length).ToArray(); - return res; + return result; } public static int DataToInt(ref byte[] data) { @@ -262,9 +326,13 @@ public static int DataToInt(ref byte[] data) if (data.Length < length) throw new IndexOutOfRangeException(); - int res = (int)((data[0] << 24) | (data[1] << 16) | data[2] << 8 | data[3]); + int result = (int)data[0] << 24 | + (int)data[1] << 16 | + (int)data[2] << 8 | + (int)data[3]; + data = data.Skip(length).ToArray(); - return res; + return result; } public static uint DataToUInt(ref byte[] data) { @@ -272,9 +340,13 @@ public static uint DataToUInt(ref byte[] data) if (data.Length < length) throw new IndexOutOfRangeException(); - uint res = (uint)((data[0] << 24) | (data[1] << 16) | data[2] << 8 | data[3]); + uint result = (uint)data[0] << 24 | + (uint)data[1] << 16 | + (uint)data[2] << 8 | + (uint)data[3]; + data = data.Skip(length).ToArray(); - return res; + return result; } public static long DataToLong(ref byte[] data) { @@ -282,9 +354,17 @@ public static long DataToLong(ref byte[] data) if (data.Length < length) throw new IndexOutOfRangeException(); - long res = (long)((((long)data[0]) << 56) | (((long)data[1]) << 48) | (((long)data[2]) << 40) | (((long)data[3]) << 32) | (((long)data[4]) << 24) | (((long)data[5]) << 16) | ((long)data[6]) << 8 | ((long)data[7])); + long result = (long)data[0] << 56 | + (long)data[1] << 48 | + (long)data[2] << 40 | + (long)data[3] << 32 | + (long)data[4] << 24 | + (long)data[5] << 16 | + (long)data[6] << 8 | + (long)data[7]; + data = data.Skip(length).ToArray(); - return res; + return result; } public static ulong DataToULong(ref byte[] data) { @@ -292,10 +372,72 @@ public static ulong DataToULong(ref byte[] data) if (data.Length < length) throw new IndexOutOfRangeException(); - ulong res = (ulong)((((ulong)data[0]) << 56) | (((ulong)data[1]) << 48) | (((ulong)data[2]) << 40) | (((ulong)data[3]) << 32) | (((ulong)data[4]) << 24) | (((ulong)data[5]) << 16) | ((ulong)data[6]) << 8 | ((ulong)data[7])); + ulong result = (ulong)data[0] << 56 | + (ulong)data[1] << 48 | + (ulong)data[2] << 40 | + (ulong)data[3] << 32 | + (ulong)data[4] << 24 | + (ulong)data[5] << 16 | + (ulong)data[6] << 8 | + (ulong)data[7]; + data = data.Skip(length).ToArray(); - return res; - } + return result; + } +#if NET7_0_OR_GREATER + public static Int128 DataToInt128(ref byte[] data) + { + const int length = 16; + if (data.Length < length) + throw new IndexOutOfRangeException(); + + Int128 result = (Int128)data[0] << 120 | + (Int128)data[1] << 112 | + (Int128)data[2] << 104 | + (Int128)data[3] << 96 | + (Int128)data[4] << 88 | + (Int128)data[5] << 80 | + (Int128)data[6] << 72 | + (Int128)data[7] << 64 | + (Int128)data[8] << 56 | + (Int128)data[9] << 48 | + (Int128)data[10] << 40 | + (Int128)data[11] << 32 | + (Int128)data[12] << 24 | + (Int128)data[13] << 16 | + (Int128)data[14] << 8 | + (Int128)data[15]; + + data = data.Skip(length).ToArray(); + return result; + } + public static UInt128 DataToUInt128(ref byte[] data) + { + const int length = 16; + if (data.Length < length) + throw new IndexOutOfRangeException(); + + UInt128 result = (UInt128)data[0] << 120 | + (UInt128)data[1] << 112 | + (UInt128)data[2] << 104 | + (UInt128)data[3] << 96 | + (UInt128)data[4] << 88 | + (UInt128)data[5] << 80 | + (UInt128)data[6] << 72 | + (UInt128)data[7] << 64 | + (UInt128)data[8] << 56 | + (UInt128)data[9] << 48 | + (UInt128)data[10] << 40 | + (UInt128)data[11] << 32 | + (UInt128)data[12] << 24 | + (UInt128)data[13] << 16 | + (UInt128)data[14] << 8 | + (UInt128)data[15]; + + data = data.Skip(length).ToArray(); + return result; + } +#endif public static UID DataToRDMUID(ref byte[] data) { const int length = 6; @@ -430,5 +572,20 @@ public static IReadOnlyDictionary AsReadOnly(this IDictionary return new ReadOnlyDictionary(source); } + public static ECommandDublicte ConvertCommandDublicteToCommand(ERDM_Command v) + { + switch (v) + { + case ERDM_Command.GET_COMMAND: + return ECommandDublicte.GetRequest; + case ERDM_Command.GET_COMMAND_RESPONSE: + return ECommandDublicte.GetResponse; + case ERDM_Command.SET_COMMAND: + return ECommandDublicte.SetRequest; + case ERDM_Command.SET_COMMAND_RESPONSE: + return ECommandDublicte.SetResponse; + } + throw new NotSupportedException(); + } } } diff --git a/RDMSharp/RDMSharp.csproj b/RDMSharp/RDMSharp.csproj index 14b7403..1c91d08 100644 --- a/RDMSharp/RDMSharp.csproj +++ b/RDMSharp/RDMSharp.csproj @@ -1,6 +1,6 @@  - netstandard2.0;net6.0;net7.0;net8.0 + net6.0;net7.0;net8.0 LICENSE 0.0.13 https://github.com/DMXControl/RDMSharp @@ -32,6 +32,11 @@ - + + + + + + diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/BOOT_SOFTWARE_VERSION_ID.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/BOOT_SOFTWARE_VERSION_ID.json new file mode 100644 index 0000000..9d08e03 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/BOOT_SOFTWARE_VERSION_ID.json @@ -0,0 +1,14 @@ +{ + "name": "BOOT_SOFTWARE_VERSION_ID", + "manufacturer_id": 0, + "pid": 193, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "boot_software_version_id", + "type": "uint32" + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/BOOT_SOFTWARE_VERSION_LABEL.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/BOOT_SOFTWARE_VERSION_LABEL.json new file mode 100644 index 0000000..74a51c2 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/BOOT_SOFTWARE_VERSION_LABEL.json @@ -0,0 +1,16 @@ +{ + "name": "BOOT_SOFTWARE_VERSION_LABEL", + "manufacturer_id": 0, + "pid": 194, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "boot_software_version_label", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/CAPTURE_PRESET.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/CAPTURE_PRESET.json new file mode 100644 index 0000000..5054209 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/CAPTURE_PRESET.json @@ -0,0 +1,35 @@ +{ + "name": "CAPTURE_PRESET", + "notes": "Either the first field or all four fields can be given.", + "manufacturer_id": 0, + "pid": 4144, + "version": 1, + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "scene_num", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "up_fade_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "down_fade_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "wait_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/CLEAR_STATUS_ID.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/CLEAR_STATUS_ID.json new file mode 100644 index 0000000..56c00b8 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/CLEAR_STATUS_ID.json @@ -0,0 +1,9 @@ +{ + "name": "CLEAR_STATUS_ID", + "manufacturer_id": 0, + "pid": 50, + "version": 1, + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/COMMS_STATUS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/COMMS_STATUS.json new file mode 100644 index 0000000..bdf738d --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/COMMS_STATUS.json @@ -0,0 +1,16 @@ +{ + "name": "COMMS_STATUS", + "manufacturer_id": 0, + "pid": 21, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [], + "get_response": [ + { "name": "short_message", "type": "uint16" }, + { "name": "length_mismatch", "type": "uint16" }, + { "name": "checksum_fail", "type": "uint16" } + ], + "set_request_subdevice_range": [ "root" ], + "set_request": [], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEFAULT_SLOT_VALUE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEFAULT_SLOT_VALUE.json new file mode 100644 index 0000000..9a85a1a --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEFAULT_SLOT_VALUE.json @@ -0,0 +1,21 @@ +{ + "name": "DEFAULT_SLOT_VALUE", + "manufacturer_id": 0, + "pid": 290, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "slots", + "type": "list", + "itemType": { + "type": "compound", + "subtypes": [ + { "name": "id", "type": "uint16" }, + { "name": "default_value", "type": "uint8" } + ] + } + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_HOURS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_HOURS.json new file mode 100644 index 0000000..c4af096 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_HOURS.json @@ -0,0 +1,14 @@ +{ + "name": "DEVICE_HOURS", + "manufacturer_id": 0, + "pid": 1024, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { "name": "hours", "type": "uint32" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_INFO.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_INFO.json new file mode 100644 index 0000000..70dc7c3 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_INFO.json @@ -0,0 +1,109 @@ +{ + "name": "DEVICE_INFO", + "manufacturer_id": 0, + "pid": 96, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { "name": "protocol_major", "type": "uint8" }, + { "name": "protocol_minor", "type": "uint8" }, + { "name": "device_model_id", "type": "uint16" }, + { + "name": "product_category", + "type": "uint16", + "labels": [ + { "name": "NOT_DECLARED", "value": 0 }, + { "name": "FIXTURE", "value": 256 }, + { "name": "FIXTURE_FIXED", "value": 257 }, + { "name": "FIXTURE_MOVING_YOKE", "value": 258 }, + { "name": "FIXTURE_MOVING_MIRROR", "value": 259 }, + { "name": "FIXTURE_OTHER", "value": 511 }, + { "name": "FIXTURE_ACCESSORY", "value": 512 }, + { "name": "FIXTURE_ACCESSORY_COLOR", "value": 513 }, + { "name": "FIXTURE_ACCESSORY_YOKE", "value": 514 }, + { "name": "FIXTURE_ACCESSORY_MIRROR", "value": 515 }, + { "name": "FIXTURE_ACCESSORY_EFFECT", "value": 516 }, + { "name": "FIXTURE_ACCESSORY_BEAM", "value": 517 }, + { "name": "FIXTURE_ACCESSORY_OTHER", "value": 767 }, + { "name": "PROJECTOR", "value": 768 }, + { "name": "PROJECTOR_FIXED", "value": 769 }, + { "name": "PROJECTOR_MOVING_YOKE", "value": 770 }, + { "name": "PROJECTOR_MOVING_MIRROR", "value": 771 }, + { "name": "PROJECTOR_OTHER", "value": 1023 }, + { "name": "ATMOSPHERIC", "value": 1024 }, + { "name": "ATMOSPHERIC_EFFECT", "value": 1025 }, + { "name": "ATMOSPHERIC_PYRO", "value": 1026 }, + { "name": "ATMOSPHERIC_OTHER", "value": 1279 }, + { "name": "DIMMER", "value": 1280 }, + { "name": "DIMMER_AC_INCANDESCENT", "value": 1281 }, + { "name": "DIMMER_AC_FLUORESCENT", "value": 1282 }, + { "name": "DIMMER_AC_COLD_CATHODE", "value": 1283 }, + { "name": "DIMMER_AC_NONDIM", "value": 1284 }, + { "name": "DIMMER_AC_ELV", "value": 1285 }, + { "name": "DIMMER_AC_OTHER", "value": 1286 }, + { "name": "DIMMER_DC_LEVEL", "value": 1287 }, + { "name": "DIMMER_DC_PWM", "value": 1288 }, + { "name": "DIMMER_CS_LED", "value": 1289 }, + { "name": "DIMMER_OTHER", "value": 1535 }, + { "name": "POWER", "value": 1536 }, + { "name": "POWER_CONTROL", "value": 1537 }, + { "name": "POWER_SOURCE", "value": 1538 }, + { "name": "POWER_OTHER", "value": 1791 }, + { "name": "SCENIC", "value": 1792 }, + { "name": "SCENIC_DRIVE", "value": 1793 }, + { "name": "SCENIC_OTHER", "value": 2047 }, + { "name": "DATA", "value": 2048 }, + { "name": "DATA_DISTRIBUTION", "value": 2049 }, + { "name": "DATA_CONVERSION", "value": 2050 }, + { "name": "DATA_OTHER", "value": 2303 }, + { "name": "AV", "value": 2304 }, + { "name": "AV_AUDIO", "value": 2305 }, + { "name": "AV_VIDEO", "value": 2306 }, + { "name": "AV_OTHER", "value": 2559 }, + { "name": "MONITOR", "value": 2560 }, + { "name": "MONITOR_AC_LINE_POWER", "value": 2561 }, + { "name": "MONITOR_DC_POWER", "value": 2562 }, + { "name": "MONITOR_ENVIRONMENTAL", "value": 2563 }, + { "name": "MONITOR_OTHER", "value": 2815 }, + { "name": "CONTROL", "value": 28672 }, + { "name": "CONTROL_CONTROLLER", "value": 28673 }, + { "name": "CONTROL_BACKUP_DEVICE", "value": 28674 }, + { "name": "CONTROL_OTHER", "value": 28927 }, + { "name": "TEST", "value": 28928 }, + { "name": "TEST_EQUIPMENT", "value": 28929 }, + { "name": "TEST_OTHER", "value": 29183 }, + { "name": "OTHER", "value": 32767 } + ] + }, + { "name": "software_version_id", "type": "uint32" }, + { + "name": "dmx_footprint", + "type": "uint16", + "ranges": [ + { "minimum": 0, "maximum": 512 } + ] + }, + { + "name": "current_personality", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + }, + { "name": "personality_count", "type": "uint8" }, + { + "name": "dmx_start_address", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 512 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "No Footprint", "value": 65535 } + ] + }, + { "name": "sub_device_count", "type": "uint16" }, + { "name": "sensor_count", "type": "uint8" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_LABEL.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_LABEL.json new file mode 100644 index 0000000..37a523e --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_LABEL.json @@ -0,0 +1,19 @@ +{ + "name": "DEVICE_LABEL", + "manufacturer_id": 0, + "pid": 130, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "label", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_MODEL_DESCRIPTION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_MODEL_DESCRIPTION.json new file mode 100644 index 0000000..ffee24b --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_MODEL_DESCRIPTION.json @@ -0,0 +1,16 @@ +{ + "name": "DEVICE_MODEL_DESCRIPTION", + "manufacturer_id": 0, + "pid": 128, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "description", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_POWER_CYCLES.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_POWER_CYCLES.json new file mode 100644 index 0000000..d100b5f --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DEVICE_POWER_CYCLES.json @@ -0,0 +1,14 @@ +{ + "name": "DEVICE_POWER_CYCLES", + "manufacturer_id": 0, + "pid": 1029, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { "name": "power_cycle_count", "type": "uint32" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DISPLAY_INVERT.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DISPLAY_INVERT.json new file mode 100644 index 0000000..8941c00 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DISPLAY_INVERT.json @@ -0,0 +1,23 @@ +{ + "name": "DISPLAY_INVERT", + "manufacturer_id": 0, + "pid": 1280, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "setting", + "type": "uint8", + "labels": [ + { "name": "Off", "value": 0 }, + { "name": "On", "value": 1 }, + { "name": "Auto", "value": 2 } + ], + "restrictToLabeled": true + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DISPLAY_LEVEL.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DISPLAY_LEVEL.json new file mode 100644 index 0000000..7369a06 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DISPLAY_LEVEL.json @@ -0,0 +1,21 @@ +{ + "name": "DISPLAY_LEVEL", + "manufacturer_id": 0, + "pid": 1281, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "level", + "type": "uint8", + "labels": [ + { "name": "Off", "value": 0 }, + { "name": "Full", "value": 255 } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DMX_PERSONALITY.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DMX_PERSONALITY.json new file mode 100644 index 0000000..3e90e6e --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DMX_PERSONALITY.json @@ -0,0 +1,23 @@ +{ + "name": "DMX_PERSONALITY", + "manufacturer_id": 0, + "pid": 224, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "personality", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + }, + { "name": "personality_count", "type": "uint8" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { "$ref": "#/get_response/0" } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DMX_PERSONALITY_DESCRIPTION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DMX_PERSONALITY_DESCRIPTION.json new file mode 100644 index 0000000..d4c953a --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DMX_PERSONALITY_DESCRIPTION.json @@ -0,0 +1,32 @@ +{ + "name": "DMX_PERSONALITY_DESCRIPTION", + "manufacturer_id": 0, + "pid": 225, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "personality", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + } + ], + "get_response": [ + { "name": "personality", "type": "uint8" }, + { + "name": "dmx_slots_required", + "type": "uint16", + "ranges": [ + { "minimum": 0, "maximum": 512 } + ] + }, + { + "name": "description", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DMX_START_ADDRESS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DMX_START_ADDRESS.json new file mode 100644 index 0000000..9ec7246 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/DMX_START_ADDRESS.json @@ -0,0 +1,32 @@ +{ + "name": "DMX_START_ADDRESS", + "manufacturer_id": 0, + "pid": 240, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "dmx_address", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 512 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "No Footprint", "value": 65535 } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "dmx_address", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 512 } + ] + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/FACTORY_DEFAULTS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/FACTORY_DEFAULTS.json new file mode 100644 index 0000000..59c01ae --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/FACTORY_DEFAULTS.json @@ -0,0 +1,17 @@ +{ + "name": "FACTORY_DEFAULTS", + "manufacturer_id": 0, + "pid": 144, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "status", + "type": "boolean" + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/IDENTIFY_DEVICE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/IDENTIFY_DEVICE.json new file mode 100644 index 0000000..550c141 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/IDENTIFY_DEVICE.json @@ -0,0 +1,21 @@ +{ + "name": "IDENTIFY_DEVICE", + "manufacturer_id": 0, + "pid": 4096, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "state", + "type": "boolean", + "labels": [ + { "name": "Off", "value": false }, + { "name": "On", "value": true } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LAMP_HOURS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LAMP_HOURS.json new file mode 100644 index 0000000..468e8d4 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LAMP_HOURS.json @@ -0,0 +1,14 @@ +{ + "name": "LAMP_HOURS", + "manufacturer_id": 0, + "pid": 1025, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { "name": "hours", "type": "uint32" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LAMP_ON_MODE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LAMP_ON_MODE.json new file mode 100644 index 0000000..25c47b4 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LAMP_ON_MODE.json @@ -0,0 +1,23 @@ +{ + "name": "LAMP_ON_MODE", + "manufacturer_id": 0, + "pid": 1028, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "mode", + "type": "uint8", + "labels": [ + { "name": "OFF", "value": 0 }, + { "name": "DMX", "value": 1 }, + { "name": "ON", "value": 2 }, + { "name": "AFTER_CAL", "value": 3 } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LAMP_STATE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LAMP_STATE.json new file mode 100644 index 0000000..5bc6fdf --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LAMP_STATE.json @@ -0,0 +1,25 @@ +{ + "name": "LAMP_STATE", + "manufacturer_id": 0, + "pid": 1027, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "state", + "type": "uint8", + "labels": [ + { "name": "LAMP_OFF", "value": 0 }, + { "name": "LAMP_ON", "value": 1 }, + { "name": "LAMP_STRIKE", "value": 2 }, + { "name": "LAMP_STANDBY", "value": 3 }, + { "name": "LAMP_NOT_PRESENT", "value": 4 }, + { "name": "LAMP_ERROR", "value": 127 } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LAMP_STRIKES.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LAMP_STRIKES.json new file mode 100644 index 0000000..0e4e4fa --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LAMP_STRIKES.json @@ -0,0 +1,14 @@ +{ + "name": "LAMP_STRIKES", + "manufacturer_id": 0, + "pid": 1026, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { "name": "strikes", "type": "uint32" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LANGUAGE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LANGUAGE.json new file mode 100644 index 0000000..f77b87a --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LANGUAGE.json @@ -0,0 +1,21 @@ +{ + "name": "LANGUAGE", + "manufacturer_id": 0, + "pid": 176, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "language_code", + "type": "string", + "pattern": "^[a-zA-Z]{2}$", + "resources": [ "https://en.wikipedia.org/wiki/ISO_639-1" ], + "minLength": 2, + "maxLength": 2 + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LANGUAGE_CAPABILITIES.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LANGUAGE_CAPABILITIES.json new file mode 100644 index 0000000..6cb7027 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/LANGUAGE_CAPABILITIES.json @@ -0,0 +1,22 @@ +{ + "name": "LANGUAGE_CAPABILITIES", + "manufacturer_id": 0, + "pid": 160, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "language_codes", + "type": "list", + "itemType": { + "name": "language_code", + "type": "string", + "pattern": "^[a-zA-Z]{2}$", + "resources": [ "https://en.wikipedia.org/wiki/ISO_639-1" ], + "minLength": 2, + "maxLength": 2 + } + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/MANUFACTURER_LABEL.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/MANUFACTURER_LABEL.json new file mode 100644 index 0000000..516f466 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/MANUFACTURER_LABEL.json @@ -0,0 +1,16 @@ +{ + "name": "MANUFACTURER_LABEL", + "manufacturer_id": 0, + "pid": 129, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "description", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PAN_INVERT.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PAN_INVERT.json new file mode 100644 index 0000000..127211c --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PAN_INVERT.json @@ -0,0 +1,21 @@ +{ + "name": "PAN_INVERT", + "manufacturer_id": 0, + "pid": 1536, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "setting", + "type": "boolean", + "labels": [ + { "name": "Off", "value": false }, + { "name": "On", "value": true } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PAN_TILT_SWAP.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PAN_TILT_SWAP.json new file mode 100644 index 0000000..e54cfec --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PAN_TILT_SWAP.json @@ -0,0 +1,21 @@ +{ + "name": "PAN_TILT_SWAP", + "manufacturer_id": 0, + "pid": 1538, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "setting", + "type": "boolean", + "labels": [ + { "name": "Off", "value": false }, + { "name": "On", "value": true } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PARAMETER_DESCRIPTION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PARAMETER_DESCRIPTION.json new file mode 100644 index 0000000..1dcc40c --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PARAMETER_DESCRIPTION.json @@ -0,0 +1,101 @@ +{ + "name": "PARAMETER_DESCRIPTION", + "manufacturer_id": 0, + "pid": 81, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { "name": "pid", "type": "uint16" } + ], + "get_response": [ + { "name": "pid", "type": "uint16" }, + { "name": "pdl", "type": "uint8" }, + { "name": "data_type", "type": "uint8" }, + { + "name": "command_class", + "type": "uint8", + "labels": [ + { "name": "GET", "value": 1 }, + { "name": "SET", "value": 2 }, + { "name": "GET_SET", "value": 3 } + ], + "restrictToLabeled": true + }, + { "name": "type", "type": "uint8" }, + { + "name": "unit", + "type": "uint8", + "labels": [ + { "name": "NONE", "value": 0 }, + { "name": "CENTIGRADE", "value": 1 }, + { "name": "VOLTS_DC", "value": 2 }, + { "name": "VOLTS_AC_PEAK", "value": 3 }, + { "name": "VOLTS_AC_RMS", "value": 4 }, + { "name": "AMPERE_DC", "value": 5 }, + { "name": "AMPERE_AC_PEAK", "value": 6 }, + { "name": "AMPERE_AC_RMS", "value": 7 }, + { "name": "HERTZ", "value": 8 }, + { "name": "OHM", "value": 9 }, + { "name": "WATT", "value": 10 }, + { "name": "KILOGRAM", "value": 11 }, + { "name": "METERS", "value": 12 }, + { "name": "METERS_SQUARED", "value": 13 }, + { "name": "METERS_CUBED", "value": 14 }, + { "name": "KILOGRAMS_PER_METERS_CUBED", "value": 15 }, + { "name": "METERS_PER_SECOND", "value": 16 }, + { "name": "METERS_PER_SECOND_SQUARED", "value": 17 }, + { "name": "NEWTON", "value": 18 }, + { "name": "JOULE", "value": 19 }, + { "name": "PASCAL", "value": 20 }, + { "name": "SECOND", "value": 21 }, + { "name": "DEGREE", "value": 22 }, + { "name": "STERADIAN", "value": 23 }, + { "name": "CANDELA", "value": 24 }, + { "name": "LUMEN", "value": 25 }, + { "name": "LUX", "value": 26 }, + { "name": "IRE", "value": 27 }, + { "name": "BYTE", "value": 28 }, + { "name": "DECIBEL", "value": 29 }, + { "name": "DECIBEL_VOLT", "value": 30 }, + { "name": "DECIBEL_WATT", "value": 31 }, + { "name": "DECIBEL_METER", "value": 32 }, + { "name": "PERCENT", "value": 33 } + ] + }, + { + "name": "unit_prefix", + "type": "uint8", + "labels": [ + { "name": "NONE", "value": 0 }, + { "name": "DECI", "value": 1 }, + { "name": "CENTI", "value": 2 }, + { "name": "MILLI", "value": 3 }, + { "name": "MICRO", "value": 4 }, + { "name": "NANO", "value": 5 }, + { "name": "PICO", "value": 6 }, + { "name": "FEMTO", "value": 7 }, + { "name": "ATTO", "value": 8 }, + { "name": "ZEPTO", "value": 9 }, + { "name": "YOCTO", "value": 10 }, + { "name": "DECA", "value": 17 }, + { "name": "HEPTO", "value": 18 }, + { "name": "KILO", "value": 19 }, + { "name": "MEGA", "value": 20 }, + { "name": "GIGA", "value": 21 }, + { "name": "TERA", "value": 22 }, + { "name": "PETA", "value": 23 }, + { "name": "EXA", "value": 24 }, + { "name": "ZETTA", "value": 25 }, + { "name": "YOTTA", "value": 26 } + ] + }, + { "name": "min_valid_value", "type": "uint32" }, + { "name": "max_valid_value", "type": "uint32" }, + { "name": "default_value", "type": "uint32" }, + { + "name": "description", + "type": "string", + "maxLength": 32 + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PERFORM_SELF_TEST.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PERFORM_SELF_TEST.json new file mode 100644 index 0000000..95e7b24 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PERFORM_SELF_TEST.json @@ -0,0 +1,23 @@ +{ + "name": "PERFORM_SELF_TEST", + "manufacturer_id": 0, + "pid": 4128, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { "name": "self_tests_active", "type": "boolean" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "self_test_num", + "type": "uint8", + "labels": [ + { "name": "SELF_TEST_OFF", "value": 0 }, + { "name": "SELF_TEST_ALL", "value": 255 } + ] + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/POWER_STATE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/POWER_STATE.json new file mode 100644 index 0000000..c379f26 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/POWER_STATE.json @@ -0,0 +1,24 @@ +{ + "name": "POWER_STATE", + "manufacturer_id": 0, + "pid": 4112, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "state", + "type": "uint8", + "labels": [ + { "name": "FULL_OFF", "value": 0 }, + { "name": "SHUTDOWN", "value": 1 }, + { "name": "STANDBY", "value": 2 }, + { "name": "NORMAL", "value": 255 } + ], + "restrictToLabeled": true + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PRESET_PLAYBACK.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PRESET_PLAYBACK.json new file mode 100644 index 0000000..5ba91ee --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PRESET_PLAYBACK.json @@ -0,0 +1,22 @@ +{ + "name": "PRESET_PLAYBACK", + "manufacturer_id": 0, + "pid": 4145, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "mode", + "type": "uint16", + "labels": [ + { "name": "OFF", "value": 0 }, + { "name": "ALL", "value": 65535 } + ] + }, + { "name": "level", "type": "uint8" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PRODUCT_DETAIL_ID_LIST.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PRODUCT_DETAIL_ID_LIST.json new file mode 100644 index 0000000..188c4e9 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PRODUCT_DETAIL_ID_LIST.json @@ -0,0 +1,99 @@ +{ + "name": "PRODUCT_DETAIL_ID_LIST", + "manufacturer_id": 0, + "pid": 112, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "product_detail_ids", + "type": "list", + "itemType": { + "name": "product_detail_id", + "type": "uint16", + "labels": [ + { "name": "NOT_DECLARED", "value": 0 }, + { "name": "ARC", "value": 1 }, + { "name": "METAL_HALIDE", "value": 2 }, + { "name": "INCANDESCENT", "value": 3 }, + { "name": "LED", "value": 4 }, + { "name": "FLUORESCENT", "value": 5 }, + { "name": "COLD_CATHODE", "value": 6 }, + { "name": "ELECTROLUMINESCENT", "value": 7 }, + { "name": "LASER", "value": 8 }, + { "name": "FLASHTUBE", "value": 9 }, + { "name": "COLOR_SCROLLER", "value": 256 }, + { "name": "COLOR_WHEEL", "value": 257 }, + { "name": "COLOR_CHANGE", "value": 258 }, + { "name": "IRIS_DOUSER", "value": 259 }, + { "name": "DIMMING_SHUTTER", "value": 260 }, + { "name": "PROFILE_SHUTTER", "value": 261 }, + { "name": "BARNDOOR_SHUTTER", "value": 262 }, + { "name": "EFFECTS_DISC", "value": 263 }, + { "name": "GOBO_ROTATOR", "value": 264 }, + { "name": "VIDEO", "value": 512 }, + { "name": "SLIDE", "value": 513 }, + { "name": "FILM", "value": 514 }, + { "name": "OIL_WHEEL", "value": 515 }, + { "name": "LCD_GATE", "value": 516 }, + { "name": "FOGGER_GLYCOL", "value": 768 }, + { "name": "FOGGER_MINERAL_OIL", "value": 769 }, + { "name": "FOGGER_WATER", "value": 770 }, + { "name": "CO2", "value": 771 }, + { "name": "LN2", "value": 772 }, + { "name": "BUBBLE", "value": 773 }, + { "name": "FLAME_PROPANE", "value": 774 }, + { "name": "FLAME_OTHER", "value": 775 }, + { "name": "OLFACTORY_STIMULATOR", "value": 776 }, + { "name": "SNOW", "value": 777 }, + { "name": "WATER_JET", "value": 778 }, + { "name": "WIND", "value": 779 }, + { "name": "CONFETTI", "value": 780 }, + { "name": "HAZARD", "value": 781 }, + { "name": "PHASE_CONTROL", "value": 1024 }, + { "name": "REVERSE_PHASE_CONTROL", "value": 1025 }, + { "name": "SINE", "value": 1026 }, + { "name": "PWM", "value": 1027 }, + { "name": "DC", "value": 1028 }, + { "name": "HF_BALLAST", "value": 1029 }, + { "name": "HFHV_NEON_BALLAST", "value": 1030 }, + { "name": "HFHV_EL", "value": 1031 }, + { "name": "MHR_BALLAST", "value": 1032 }, + { "name": "BIT_ANGLE_MODULATION", "value": 1033 }, + { "name": "HIGH_FREQUENCY_12V", "value": 1034 }, + { "name": "RELAY_MECHANICAL", "value": 1035 }, + { "name": "RELAY_ELECTRONIC", "value": 1036 }, + { "name": "SWITCH_ELECTRONIC", "value": 1037 }, + { "name": "CONTACTOR", "value": 1037 }, + { "name": "MIRROR_BALL_ROTATOR", "value": 1280 }, + { "name": "OTHER_ROTATOR", "value": 1281 }, + { "name": "KABUKI_DROP", "value": 1282 }, + { "name": "CURTAIN", "value": 1283 }, + { "name": "LINESET", "value": 1284 }, + { "name": "MOTOR_CONTROL", "value": 1285 }, + { "name": "DAMPER_CONTROL", "value": 1286 }, + { "name": "SPLITTER", "value": 1536 }, + { "name": "ETHERNET_NODE", "value": 1537 }, + { "name": "MERGE", "value": 1538 }, + { "name": "DATAPATCH", "value": 1539 }, + { "name": "WIRELESS_LINK", "value": 1540 }, + { "name": "PROTOCOL_CONVERTER", "value": 1793 }, + { "name": "ANALOG_DEMULTIPLEX", "value": 1794 }, + { "name": "ANALOG_MULTIPLEX", "value": 1795 }, + { "name": "SWITCH_PANEL", "value": 1796 }, + { "name": "ROUTER", "value": 2048 }, + { "name": "FADER", "value": 2049 }, + { "name": "MIXER", "value": 2050 }, + { "name": "CHANGEOVER_MANUAL", "value": 2304 }, + { "name": "CHANGEOVER_AUTO", "value": 2305 }, + { "name": "TEST", "value": 2036 }, + { "name": "GFI_RCD", "value": 2560 }, + { "name": "BATTERY", "value": 2561 }, + { "name": "CONTROLLABLE_BREAKER", "value": 2562 }, + { "name": "OTHER", "value": 32767 } + ] + } + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PROXIED_DEVICES.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PROXIED_DEVICES.json new file mode 100644 index 0000000..01ffafd --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PROXIED_DEVICES.json @@ -0,0 +1,19 @@ +{ + "name": "PROXIED_DEVICES", + "manufacturer_id": 0, + "pid": 16, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [], + "get_response": [ + { + "name": "device_uids", + "type": "list", + "itemType": { + "name": "device_uid", + "type": "bytes", + "format": "uid" + } + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PROXIED_DEVICE_COUNT.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PROXIED_DEVICE_COUNT.json new file mode 100644 index 0000000..348fc8f --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/PROXIED_DEVICE_COUNT.json @@ -0,0 +1,12 @@ +{ + "name": "PROXIED_DEVICE_COUNT", + "manufacturer_id": 0, + "pid": 17, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [], + "get_response": [ + { "name": "device_count", "type": "uint16" }, + { "name": "list_change", "type": "boolean" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/QUEUED_MESSAGE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/QUEUED_MESSAGE.json new file mode 100644 index 0000000..eed499b --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/QUEUED_MESSAGE.json @@ -0,0 +1,22 @@ +{ + "name": "QUEUED_MESSAGE", + "manufacturer_id": 0, + "pid": 32, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "status_type", + "type": "uint8", + "labels": [ + { "name": "STATUS_NONE", "value": 0 }, + { "name": "STATUS_GET_LAST_MESSAGE", "value": 1 }, + { "name": "STATUS_ADVISORY", "value": 2 }, + { "name": "STATUS_WARNING", "value": 3 }, + { "name": "STATUS_ERROR", "value": 4 } + ], + "restrictToLabeled": true + } + ], + "get_response": "different_pid" +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/REAL_TIME_CLOCK.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/REAL_TIME_CLOCK.json new file mode 100644 index 0000000..260937a --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/REAL_TIME_CLOCK.json @@ -0,0 +1,55 @@ +{ + "name": "REAL_TIME_CLOCK", + "manufacturer_id": 0, + "pid": 1539, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "year", + "type": "uint16", + "ranges": [ + { "minimum": 2003, "maximum": 65535 } + ] + }, + { + "name": "month", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 12 } + ] + }, + { + "name": "day", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 31 } + ] + }, + { + "name": "hour", + "type": "uint8", + "ranges": [ + { "minimum": 0, "maximum": 24 } + ] + }, + { + "name": "minute", + "type": "uint8", + "ranges": [ + { "minimum": 0, "maximum": 59 } + ] + }, + { + "name": "second", + "type": "uint8", + "ranges": [ + { "minimum": 0, "maximum": 60 } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/RECORD_SENSORS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/RECORD_SENSORS.json new file mode 100644 index 0000000..636941e --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/RECORD_SENSORS.json @@ -0,0 +1,11 @@ +{ + "name": "RECORD_SENSORS", + "manufacturer_id": 0, + "pid": 514, + "version": 1, + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { "name": "sensor", "type": "uint8" } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/RESET_DEVICE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/RESET_DEVICE.json new file mode 100644 index 0000000..5ca68fa --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/RESET_DEVICE.json @@ -0,0 +1,19 @@ +{ + "name": "RESET_DEVICE", + "manufacturer_id": 0, + "pid": 4097, + "version": 1, + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "state", + "type": "uint8", + "labels": [ + { "name": "Warm Reset", "value": 1 }, + { "name": "Cold Reset", "value": 255 } + ], + "restrictToLabeled": true + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SELF_TEST_DESCRIPTION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SELF_TEST_DESCRIPTION.json new file mode 100644 index 0000000..918bf5c --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SELF_TEST_DESCRIPTION.json @@ -0,0 +1,19 @@ +{ + "name": "SELF_TEST_DESCRIPTION", + "manufacturer_id": 0, + "pid": 4129, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { "name": "self_test_num", "type": "uint8" } + ], + "get_response": [ + { "name": "self_test_num", "type": "uint8" }, + { + "name": "label", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SENSOR_DEFINITION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SENSOR_DEFINITION.json new file mode 100644 index 0000000..b53cb79 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SENSOR_DEFINITION.json @@ -0,0 +1,145 @@ +{ + "name": "SENSOR_DEFINITION", + "manufacturer_id": 0, + "pid": 512, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { "name": "sensor", "type": "uint8" } + ], + "get_response": [ + { "name": "sensor", "type": "uint8" }, + { + "name": "type", + "type": "uint8", + "labels": [ + { "name": "TEMPERATURE", "value": 0 }, + { "name": "VOLTAGE", "value": 1 }, + { "name": "CURRENT", "value": 2 }, + { "name": "FREQUENCY", "value": 3 }, + { "name": "RESISTANCE", "value": 4 }, + { "name": "POWER", "value": 5 }, + { "name": "MASS", "value": 6 }, + { "name": "LENGTH", "value": 7 }, + { "name": "AREA", "value": 8 }, + { "name": "VOLUME", "value": 9 }, + { "name": "DENSITY", "value": 10 }, + { "name": "VELOCITY", "value": 11 }, + { "name": "ACCELERATION", "value": 12 }, + { "name": "FORCE", "value": 13 }, + { "name": "ENERGY", "value": 14 }, + { "name": "PRESSURE", "value": 15 }, + { "name": "TIME", "value": 16 }, + { "name": "ANGLE", "value": 17 }, + { "name": "POSITION_X", "value": 18 }, + { "name": "POSITION_Y", "value": 19 }, + { "name": "POSITION_Z", "value": 20 }, + { "name": "ANGULAR_VELOCTY", "value": 21 }, + { "name": "LUMINOUS_INTENSITY", "value": 22 }, + { "name": "LUMINOUS_FLUX", "value": 23 }, + { "name": "ILLUMINANCE", "value": 24 }, + { "name": "CHROMINANCE_RED", "value": 25 }, + { "name": "CHROMINANCE_GREEN", "value": 26 }, + { "name": "CHROMINANCE_BLUE", "value": 27 }, + { "name": "CONTACTS", "value": 28 }, + { "name": "MEMORY", "value": 29 }, + { "name": "ITEMS", "value": 30 }, + { "name": "HUMIDITY", "value": 31 }, + { "name": "COUNTER_16BIT", "value": 32 }, + { "name": "RPM", "value": 33 }, + { "name": "CPU_LOAD", "value": 34 }, + { "name": "BANDWIDTH_TOTAL", "value": 35 }, + { "name": "BANDWIDTH_USED", "value": 36 }, + { "name": "GAS_CONCENTRATION", "value": 37 }, + { "name": "CO2_LEVEL", "value": 38 }, + { "name": "SOUND_PRESSURE_LEVEL", "value": 39 }, + { "name": "OTHER", "value": 127 } + ] + }, + { + "name": "unit", + "type": "uint8", + "labels": [ + { "name": "NONE", "value": 0 }, + { "name": "CENTIGRADE", "value": 1 }, + { "name": "VOLTS_DC", "value": 2 }, + { "name": "VOLTS_AC_PEAK", "value": 3 }, + { "name": "VOLTS_AC_RMS", "value": 4 }, + { "name": "AMPERE_DC", "value": 5 }, + { "name": "AMPERE_AC_PEAK", "value": 6 }, + { "name": "AMPERE_AC_RMS", "value": 7 }, + { "name": "HERTZ", "value": 8 }, + { "name": "OHM", "value": 9 }, + { "name": "WATT", "value": 10 }, + { "name": "KILOGRAM", "value": 11 }, + { "name": "METERS", "value": 12 }, + { "name": "METERS_SQUARED", "value": 13 }, + { "name": "METERS_CUBED", "value": 14 }, + { "name": "KILOGRAMS_PER_METERS_CUBED", "value": 15 }, + { "name": "METERS_PER_SECOND", "value": 16 }, + { "name": "METERS_PER_SECOND_SQUARED", "value": 17 }, + { "name": "NEWTON", "value": 18 }, + { "name": "JOULE", "value": 19 }, + { "name": "PASCAL", "value": 20 }, + { "name": "SECOND", "value": 21 }, + { "name": "DEGREE", "value": 22 }, + { "name": "STERADIAN", "value": 23 }, + { "name": "CANDELA", "value": 24 }, + { "name": "LUMEN", "value": 25 }, + { "name": "LUX", "value": 26 }, + { "name": "IRE", "value": 27 }, + { "name": "BYTE", "value": 28 }, + { "name": "DECIBEL", "value": 29 }, + { "name": "DECIBEL_VOLT", "value": 30 }, + { "name": "DECIBEL_WATT", "value": 31 }, + { "name": "DECIBEL_METER", "value": 32 }, + { "name": "PERCENT", "value": 33 } + ] + }, + { + "name": "unit_prefix", + "type": "uint8", + "labels": [ + { "name": "NONE", "value": 0 }, + { "name": "DECI", "value": 1 }, + { "name": "CENTI", "value": 2 }, + { "name": "MILLI", "value": 3 }, + { "name": "MICRO", "value": 4 }, + { "name": "NANO", "value": 5 }, + { "name": "PICO", "value": 6 }, + { "name": "FEMTO", "value": 7 }, + { "name": "ATTO", "value": 8 }, + { "name": "ZEPTO", "value": 9 }, + { "name": "YOCTO", "value": 10 }, + { "name": "DECA", "value": 17 }, + { "name": "HEPTO", "value": 18 }, + { "name": "KILO", "value": 19 }, + { "name": "MEGA", "value": 20 }, + { "name": "GIGA", "value": 21 }, + { "name": "TERA", "value": 22 }, + { "name": "PETA", "value": 23 }, + { "name": "EXA", "value": 24 }, + { "name": "ZETTA", "value": 25 }, + { "name": "YOTTA", "value": 26 } + ] + }, + { "name": "range_min_value", "type": "int16" }, + { "name": "range_max_value", "type": "int16" }, + { "name": "normal_min_value", "type": "int16" }, + { "name": "normal_max_value", "type": "int16" }, + { + "name": "recorded_value_support", + "type": "bitField", + "size": 8, + "bits": [ + { "name": "recorded_value_supported", "index": 0 }, + { "name": "low_high_detected_values_supported", "index": 1 } + ] + }, + { + "name": "description", + "type": "string", + "maxLength": 32 + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SENSOR_VALUE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SENSOR_VALUE.json new file mode 100644 index 0000000..6ad3ba6 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SENSOR_VALUE.json @@ -0,0 +1,20 @@ +{ + "name": "SENSOR_VALUE", + "manufacturer_id": 0, + "pid": 513, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { "name": "sensor", "type": "uint8" } + ], + "get_response": [ + { "name": "sensor", "type": "uint8" }, + { "name": "value", "type": "int16" }, + { "name": "lowest_detected", "type": "int16" }, + { "name": "highest_detected", "type": "int16" }, + { "name": "recorded_value", "type": "int16" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_request", + "set_response": "get_response" +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SLOT_DESCRIPTION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SLOT_DESCRIPTION.json new file mode 100644 index 0000000..7d3fbee --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SLOT_DESCRIPTION.json @@ -0,0 +1,19 @@ +{ + "name": "SLOT_DESCRIPTION", + "manufacturer_id": 0, + "pid": 289, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { "name": "slot", "type": "uint16" } + ], + "get_response": [ + { "name": "slot", "type": "uint16" }, + { + "name": "description", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SLOT_INFO.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SLOT_INFO.json new file mode 100644 index 0000000..a25aaba --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SLOT_INFO.json @@ -0,0 +1,22 @@ +{ + "name": "SLOT_INFO", + "manufacturer_id": 0, + "pid": 288, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "slots", + "type": "list", + "itemType": { + "type": "compound", + "subtypes": [ + { "name": "id", "type": "uint16" }, + { "name": "type", "type": "uint8" }, + { "name": "label_id", "type": "uint16" } + ] + } + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SOFTWARE_VERSION_LABEL.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SOFTWARE_VERSION_LABEL.json new file mode 100644 index 0000000..0eb607d --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SOFTWARE_VERSION_LABEL.json @@ -0,0 +1,16 @@ +{ + "name": "SOFTWARE_VERSION_LABEL", + "manufacturer_id": 0, + "pid": 192, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "software_version_label", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/STATUS_ID_DESCRIPTION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/STATUS_ID_DESCRIPTION.json new file mode 100644 index 0000000..8428a76 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/STATUS_ID_DESCRIPTION.json @@ -0,0 +1,18 @@ +{ + "name": "STATUS_ID_DESCRIPTION", + "manufacturer_id": 0, + "pid": 49, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { "name": "status_id", "type": "uint16" } + ], + "get_response": [ + { + "name": "description", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/STATUS_MESSAGES.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/STATUS_MESSAGES.json new file mode 100644 index 0000000..3876d53 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/STATUS_MESSAGES.json @@ -0,0 +1,49 @@ +{ + "name": "STATUS_MESSAGES", + "manufacturer_id": 0, + "pid": 48, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "status_type", + "type": "uint8", + "notes": "The requested Status Type isn't restricted in the spec.", + "labels": [ + { "name": "STATUS_NONE", "value": 0 }, + { "name": "STATUS_GET_LAST_MESSAGE", "value": 1 }, + { "name": "STATUS_ADVISORY", "value": 2 }, + { "name": "STATUS_WARNING", "value": 3 }, + { "name": "STATUS_ERROR", "value": 4 } + ] + } + ], + "get_response": [ + { + "name": "slots", + "type": "list", + "itemType": { + "type": "compound", + "subtypes": [ + { "name": "subdevice_id", "type": "uint16" }, + { + "name": "status_type", + "type": "uint8", + "labels": [ + { "name": "STATUS_ADVISORY", "value": 2 }, + { "name": "STATUS_WARNING", "value": 3 }, + { "name": "STATUS_ERROR", "value": 4 }, + { "name": "STATUS_ADVISORY_CLEARED", "value": 18 }, + { "name": "STATUS_WARNING_CLEARED", "value": 19 }, + { "name": "STATUS_ERROR_CLEARED", "value": 20 } + ], + "restrictToLabeled": true + }, + { "name": "status_message_id", "type": "uint16" }, + { "name": "data_value_1", "type": "int16" }, + { "name": "data_value_2", "type": "int16" } + ] + } + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SUB_DEVICE_STATUS_REPORT_THRESHOLD.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SUB_DEVICE_STATUS_REPORT_THRESHOLD.json new file mode 100644 index 0000000..66f35fb --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SUB_DEVICE_STATUS_REPORT_THRESHOLD.json @@ -0,0 +1,24 @@ +{ + "name": "SUB_DEVICE_STATUS_REPORT_THRESHOLD", + "manufacturer_id": 0, + "pid": 51, + "version": 1, + "get_request_subdevice_range": [ "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "status_type", + "type": "uint8", + "notes": "The Status Type value is not restricted in the spec.", + "labels": [ + { "name": "STATUS_NONE", "value": 0 }, + { "name": "STATUS_ADVISORY", "value": 2 }, + { "name": "STATUS_WARNING", "value": 3 }, + { "name": "STATUS_ERROR", "value": 4 } + ] + } + ], + "set_request_subdevice_range": [ "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SUPPORTED_PARAMETERS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SUPPORTED_PARAMETERS.json new file mode 100644 index 0000000..dd2143e --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/SUPPORTED_PARAMETERS.json @@ -0,0 +1,18 @@ +{ + "name": "SUPPORTED_PARAMETERS", + "manufacturer_id": 0, + "pid": 80, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "pids", + "type": "list", + "itemType": { + "name": "pid", + "type": "uint16" + } + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/TILT_INVERT.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/TILT_INVERT.json new file mode 100644 index 0000000..75eb34e --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.20/TILT_INVERT.json @@ -0,0 +1,21 @@ +{ + "name": "TILT_INVERT", + "manufacturer_id": 0, + "pid": 1537, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "setting", + "type": "boolean", + "labels": [ + { "name": "Off", "value": false }, + { "name": "On", "value": true } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/BURN_IN.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/BURN_IN.json new file mode 100644 index 0000000..f608075 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/BURN_IN.json @@ -0,0 +1,23 @@ +{ + "name": "BURN_IN", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 1088, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { "name": "hours_remaining", "type": "uint8" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "hours", + "type": "uint8", + "labels": [ + { "name": "Abort", "value": 0 } + ] + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/CURVE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/CURVE.json new file mode 100644 index 0000000..fbec7d5 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/CURVE.json @@ -0,0 +1,18 @@ +{ + "name": "CURVE", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 835, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { "name": "curve", "type": "uint8" }, + { "name": "curve_count", "type": "uint8" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { "name": "curve", "type": "uint8" } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/CURVE_DESCRIPTION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/CURVE_DESCRIPTION.json new file mode 100644 index 0000000..abc6992 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/CURVE_DESCRIPTION.json @@ -0,0 +1,20 @@ +{ + "name": "CURVE_DESCRIPTION", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 836, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { "name": "curve", "type": "uint8" } + ], + "get_response": [ + { "name": "curve", "type": "uint8" }, + { + "name": "description", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/DIMMER_INFO.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/DIMMER_INFO.json new file mode 100644 index 0000000..896d4c8 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/DIMMER_INFO.json @@ -0,0 +1,55 @@ +{ + "name": "DIMMER_INFO", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 832, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "min_level_lower_limit", + "type": "uint16", + "labels": [ + { "name": "Not Implemented", "value": 0 } + ] + }, + { + "name": "min_level_upper_limit", + "type": "uint16", + "labels": [ + { "name": "Not Implemented", "value": 0 } + ] + }, + { + "name": "max_level_lower_limit", + "type": "uint16", + "labels": [ + { "name": "Not Implemented", "value": 65535 } + ] + }, + { + "name": "max_level_upper_limit", + "type": "uint16", + "labels": [ + { "name": "Not Implemented", "value": 65535 } + ] + }, + { "name": "curve_count", "type": "uint8" }, + { + "name": "levels_resolution_bits", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 16 } + ] + }, + { + "name": "min_level_split_levels_supported", + "type": "boolean", + "labels": [ + { "name": "Not Supported", "value": false }, + { "name": "Supported", "value": true } + ] + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/DMX_BLOCK_ADDRESS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/DMX_BLOCK_ADDRESS.json new file mode 100644 index 0000000..34799d3 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/DMX_BLOCK_ADDRESS.json @@ -0,0 +1,40 @@ +{ + "name": "DMX_BLOCK_ADDRESS", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 320, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [], + "get_response": [ + { + "name": "total_subdevice_footprint", + "type": "uint16", + "ranges": [ + { "minimum": 0, "maximum": 512 } + ] + }, + { + "name": "base_dmx_address", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 512 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "No Footprint", "value": 65535 } + ] + } + ], + "set_request_subdevice_range": [ "root" ], + "set_request": [ + { + "name": "base_dmx_address", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 512 } + ] + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/DMX_FAIL_MODE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/DMX_FAIL_MODE.json new file mode 100644 index 0000000..593c822 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/DMX_FAIL_MODE.json @@ -0,0 +1,47 @@ +{ + "name": "DMX_FAIL_MODE", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 321, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "scene_num", + "type": "uint16", + "labels": [ + { "name": "PRESET_PLAYBACK_OFF", "value": 0 }, + { "name": "PRESET_PLAYBACK_ALL", "value": 65535 } + ] + }, + { + "name": "loss_of_signal_delay_time", + "type": "uint16", + "units": 21, + "prefixPower": -1, + "labels": [ + { "name": "Infinite", "value": 65535 } + ] + }, + { + "name": "hold_time", + "type": "uint16", + "units": 21, + "prefixPower": -1, + "labels": [ + { "name": "Infinite", "value": 65535 } + ] + }, + { + "name": "level", + "type": "uint8", + "labels": [ + { "name": "Full", "value": 255 } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/DMX_STARTUP_MODE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/DMX_STARTUP_MODE.json new file mode 100644 index 0000000..f568ba9 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/DMX_STARTUP_MODE.json @@ -0,0 +1,44 @@ +{ + "name": "DMX_STARTUP_MODE", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 322, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "scene_num", + "type": "uint16", + "labels": [ + { "name": "PRESET_PLAYBACK_OFF", "value": 0 }, + { "name": "PRESET_PLAYBACK_ALL", "value": 65535 } + ] + }, + { + "name": "startup_delay_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "hold_time", + "type": "uint16", + "units": 21, + "prefixPower": -1, + "labels": [ + { "name": "Infinite", "value": 65535 } + ] + }, + { + "name": "level", + "type": "uint8", + "labels": [ + { "name": "Full", "value": 255 } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/IDENTIFY_MODE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/IDENTIFY_MODE.json new file mode 100644 index 0000000..7eaec5e --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/IDENTIFY_MODE.json @@ -0,0 +1,22 @@ +{ + "name": "IDENTIFY_MODE", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 4160, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "mode", + "type": "uint8", + "labels": [ + { "name": "Quiet Identify", "value": 0 }, + { "name": "Loud Identify", "value": 255 } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/LOCK_PIN.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/LOCK_PIN.json new file mode 100644 index 0000000..4d934b1 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/LOCK_PIN.json @@ -0,0 +1,36 @@ +{ + "name": "LOCK_PIN", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 1600, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "current_pin_code", + "type": "uint16", + "ranges": [ + { "minimum": 0, "maximum": 9999 } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "new_pin_code", + "type": "uint16", + "ranges": [ + { "minimum": 0, "maximum": 9999 } + ] + }, + { + "name": "current_pin_code", + "type": "uint16", + "ranges": [ + { "minimum": 0, "maximum": 9999 } + ] + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/LOCK_STATE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/LOCK_STATE.json new file mode 100644 index 0000000..a82df8d --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/LOCK_STATE.json @@ -0,0 +1,37 @@ +{ + "name": "LOCK_STATE", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 1601, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "state", + "type": "uint8", + "labels": [ + { "name": "Unlocked", "value": 0 } + ] + }, + { "name": "state_count", "type": "uint8" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "pin_code", + "type": "uint16", + "ranges": [ + { "minimum": 0, "maximum": 9999 } + ] + }, + { + "name": "state", + "type": "uint8", + "labels": [ + { "name": "Unlocked", "value": 0 } + ] + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/LOCK_STATE_DESCRIPTION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/LOCK_STATE_DESCRIPTION.json new file mode 100644 index 0000000..36cecf6 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/LOCK_STATE_DESCRIPTION.json @@ -0,0 +1,32 @@ +{ + "name": "LOCK_STATE_DESCRIPTION", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 1602, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "state", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + } + ], + "get_response": [ + { + "name": "state", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + }, + { + "name": "description", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/MAXIMUM_LEVEL.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/MAXIMUM_LEVEL.json new file mode 100644 index 0000000..4227ddc --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/MAXIMUM_LEVEL.json @@ -0,0 +1,15 @@ +{ + "name": "MAXIMUM_LEVEL", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 834, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { "name": "max_level", "type": "uint16" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/MINIMUM_LEVEL.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/MINIMUM_LEVEL.json new file mode 100644 index 0000000..fe4ea10 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/MINIMUM_LEVEL.json @@ -0,0 +1,17 @@ +{ + "name": "MINIMUM_LEVEL", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 833, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { "name": "min_level_increasing", "type": "uint16" }, + { "name": "min_level_decreasing", "type": "uint16" }, + { "name": "on_below_min", "type": "boolean" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/MODULATION_FREQUENCY.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/MODULATION_FREQUENCY.json new file mode 100644 index 0000000..aa66cd4 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/MODULATION_FREQUENCY.json @@ -0,0 +1,30 @@ +{ + "name": "MODULATION_FREQUENCY", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 839, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "setting", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + }, + { "name": "setting_count", "type": "uint8" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "setting", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/MODULATION_FREQUENCY_DESCRIPTION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/MODULATION_FREQUENCY_DESCRIPTION.json new file mode 100644 index 0000000..2dcf584 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/MODULATION_FREQUENCY_DESCRIPTION.json @@ -0,0 +1,42 @@ +{ + "name": "MODULATION_FREQUENCY_DESCRIPTION", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 840, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "setting", + "type": "uint8", + "notes": "The value isn't restricted in the spec, but MODULATION_FREQUENCY restricts this.", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + } + ], + "get_response": [ + { + "name": "setting", + "type": "uint8", + "notes": "The value isn't restricted in the spec, but MODULATION_FREQUENCY restricts this.", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + }, + { + "name": "frequency", + "type": "uint32", + "units": 8, + "labels": [ + { "name": "Not Declared", "value": 4294967295 } + ] + }, + { + "name": "description", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/OUTPUT_RESPONSE_TIME.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/OUTPUT_RESPONSE_TIME.json new file mode 100644 index 0000000..6910308 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/OUTPUT_RESPONSE_TIME.json @@ -0,0 +1,30 @@ +{ + "name": "OUTPUT_RESPONSE_TIME", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 837, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "setting", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + }, + { "name": "setting_count", "type": "uint8" } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "setting", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/OUTPUT_RESPONSE_TIME_DESCRIPTION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/OUTPUT_RESPONSE_TIME_DESCRIPTION.json new file mode 100644 index 0000000..2c96662 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/OUTPUT_RESPONSE_TIME_DESCRIPTION.json @@ -0,0 +1,34 @@ +{ + "name": "OUTPUT_RESPONSE_TIME_DESCRIPTION", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 838, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "setting", + "type": "uint8", + "notes": "The value isn't restricted in the spec, but OUTPUT_RESPONSE_TIME restricts this.", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + } + ], + "get_response": [ + { + "name": "setting", + "type": "uint8", + "notes": "The value isn't restricted in the spec, but OUTPUT_RESPONSE_TIME restricts this.", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + }, + { + "name": "description", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/POWER_ON_SELF_TEST.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/POWER_ON_SELF_TEST.json new file mode 100644 index 0000000..f3101d7 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/POWER_ON_SELF_TEST.json @@ -0,0 +1,22 @@ +{ + "name": "POWER_ON_SELF_TEST", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 4164, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "parameter", + "type": "uint8", + "labels": [ + { "name": "Disabled", "value": 0 }, + { "name": "Enabled", "value": 1 } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/PRESET_INFO.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/PRESET_INFO.json new file mode 100644 index 0000000..80ea0de --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/PRESET_INFO.json @@ -0,0 +1,114 @@ +{ + "name": "PRESET_INFO", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 4161, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { "name": "level_field_supported", "type": "boolean" }, + { "name": "preset_sequence_supported", "type": "boolean" }, + { "name": "split_times_supported", "type": "boolean" }, + { "name": "dmx_fail_infinite_delay_time_supported", "type": "boolean" }, + { "name": "dmx_fail_infinite_hold_time_supported", "type": "boolean" }, + { "name": "startup_infinite_hold_time_supported", "type": "boolean" }, + { "name": "max_scene_number", "type": "uint16" }, + { + "name": "preset_min_fade_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "preset_max_fade_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "preset_min_wait_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "preset_max_wait_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "dmx_fail_min_delay_time", + "type": "uint16", + "units": 21, + "prefixPower": -1, + "labels": [ + { "name": "Not Supported", "value": 65535 } + ] + }, + { + "name": "dmx_fail_max_delay_time", + "type": "uint16", + "units": 21, + "prefixPower": -1, + "labels": [ + { "name": "Not Supported", "value": 65535 } + ] + }, + { + "name": "dmx_fail_min_hold_time", + "type": "uint16", + "units": 21, + "prefixPower": -1, + "labels": [ + { "name": "Not Supported", "value": 65535 } + ] + }, + { + "name": "dmx_fail_max_hold_time", + "type": "uint16", + "units": 21, + "prefixPower": -1, + "labels": [ + { "name": "Not Supported", "value": 65535 } + ] + }, + { + "name": "startup_min_delay_time", + "type": "uint16", + "units": 21, + "prefixPower": -1, + "labels": [ + { "name": "Not Supported", "value": 65535 } + ] + }, + { + "name": "startup_max_delay_time", + "type": "uint16", + "units": 21, + "prefixPower": -1, + "labels": [ + { "name": "Not Supported", "value": 65535 } + ] + }, + { + "name": "startup_min_hold_time", + "type": "uint16", + "units": 21, + "prefixPower": -1, + "labels": [ + { "name": "Not Supported", "value": 65535 } + ] + }, + { + "name": "startup_max_hold_time", + "type": "uint16", + "units": 21, + "prefixPower": -1, + "labels": [ + { "name": "Not Supported", "value": 65535 } + ] + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/PRESET_MERGE_MODE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/PRESET_MERGE_MODE.json new file mode 100644 index 0000000..465f69a --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/PRESET_MERGE_MODE.json @@ -0,0 +1,26 @@ +{ + "name": "PRESET_MERGE_MODE", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 4163, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "mode", + "type": "uint8", + "labels": [ + { "name": "DEFAULT", "value": 0 }, + { "name": "HTP", "value": 1 }, + { "name": "LTP", "value": 2 }, + { "name": "DMX_ONLY", "value": 3 }, + { "name": "OTHER", "value": 255 } + ], + "restrictToLabeled": true + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/PRESET_STATUS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/PRESET_STATUS.json new file mode 100644 index 0000000..f7df384 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-1/PRESET_STATUS.json @@ -0,0 +1,91 @@ +{ + "name": "PRESET_STATUS", + "notes": "E1.37-1", + "manufacturer_id": 0, + "pid": 4162, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "scene_num", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 65534 } + ] + } + ], + "get_response": [ + { + "name": "scene_num", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 65534 } + ] + }, + { + "name": "up_fade_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "down_fade_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "wait_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "programmed", + "type": "uint8", + "labels": [ + { "name": "NOT_PROGRAMMED", "value": 0 }, + { "name": "PROGRAMMED", "value": 1 }, + { "name": "PROGRAMMED_READ_ONLY", "value": 2 } + ], + "restrictToLabeled": true + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "scene_num", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 65534 } + ] + }, + { + "name": "up_fade_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "down_fade_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "wait_time", + "type": "uint16", + "units": 21, + "prefixPower": -1 + }, + { + "name": "clear_preset", + "type": "boolean", + "labels": [ + { "name": "Don't Clear", "value": false }, + { "name": "Clear", "value": true } + ] + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/DNS_DOMAIN_NAME.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/DNS_DOMAIN_NAME.json new file mode 100644 index 0000000..2fdb9c2 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/DNS_DOMAIN_NAME.json @@ -0,0 +1,28 @@ +{ + "name": "DNS_DOMAIN_NAME", + "notes": "E1.37-2. This the domain of an internet host; it is appended to the hostname using a dot ('.') to create a fully qualified domain name (FQDN).", + "manufacturer_id": 0, + "pid": 1805, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "domain_name", + "type": "string", + "resources": [ + "https://www.rfc-editor.org/rfc/rfc1123.html#section-2", + "https://www.rfc-editor.org/rfc/rfc1912.html#section-2.1", + "https://www.rfc-editor.org/rfc/rfc1035.html#section-2.3.1", + "https://www.rfc-editor.org/rfc/rfc3696.html#section-2", + "https://stackoverflow.com/a/14622263" + ], + "format": "hostname", + "maxLength": 231, + "restrictToASCII": true + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/DNS_HOSTNAME.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/DNS_HOSTNAME.json new file mode 100644 index 0000000..a96c6f7 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/DNS_HOSTNAME.json @@ -0,0 +1,29 @@ +{ + "name": "DNS_HOSTNAME", + "notes": "E1.37-2. This the host-specific part (or \"label\") of an internet host; it is prepended to the domain name using a dot ('.') to create a fully qualified domain name (FQDN).", + "manufacturer_id": 0, + "pid": 1804, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "hostname", + "type": "string", + "resources": [ + "https://www.rfc-editor.org/rfc/rfc1123.html#section-2", + "https://www.rfc-editor.org/rfc/rfc1912.html#section-2.1", + "https://www.rfc-editor.org/rfc/rfc3696.html#section-2", + "https://stackoverflow.com/a/14622263" + ], + "pattern": "^(?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]$", + "notes": "Some implementations don't support negative lookbehind in patterns. Alternative patterns without negative lookahead: \"^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])$\", \"^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$\".", + "minLength": 1, + "maxLength": 63, + "restrictToASCII": true + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/DNS_IPV4_NAME_SERVER.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/DNS_IPV4_NAME_SERVER.json new file mode 100644 index 0000000..d4e0245 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/DNS_IPV4_NAME_SERVER.json @@ -0,0 +1,35 @@ +{ + "name": "DNS_IPV4_NAME_SERVER", + "notes": "E1.37-2", + "manufacturer_id": 0, + "pid": 1803, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "index", + "type": "uint8", + "ranges": [ + { "minimum": 0, "maximum": 2 } + ] + } + ], + "get_response": [ + { + "name": "index", + "type": "uint8", + "ranges": [ + { "minimum": 0, "maximum": 2 } + ] + }, + { + "name": "address", + "type": "bytes", + "notes": "All zeros means IPV4_UNCONFIGURED.", + "format": "ipv4" + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_APPLY_CONFIGURATION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_APPLY_CONFIGURATION.json new file mode 100644 index 0000000..46df8c9 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_APPLY_CONFIGURATION.json @@ -0,0 +1,18 @@ +{ + "name": "INTERFACE_APPLY_CONFIGURATION", + "notes": "E1.37-2", + "manufacturer_id": 0, + "pid": 1781, + "version": 1, + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_HARDWARE_ADDRESS_TYPE1.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_HARDWARE_ADDRESS_TYPE1.json new file mode 100644 index 0000000..5c2d03d --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_HARDWARE_ADDRESS_TYPE1.json @@ -0,0 +1,32 @@ +{ + "name": "INTERFACE_HARDWARE_ADDRESS_TYPE1", + "notes": "E1.37-2", + "manufacturer_id": 0, + "pid": 1794, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + } + ], + "get_response": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + }, + { + "name": "address", + "type": "bytes", + "resources": [ "https://www.rfc-editor.org/rfc/rfc7042.html#section-2.1" ], + "format": "mac-address" + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_LABEL.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_LABEL.json new file mode 100644 index 0000000..460c72e --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_LABEL.json @@ -0,0 +1,32 @@ +{ + "name": "INTERFACE_LABEL", + "notes": "E1.37-2", + "manufacturer_id": 0, + "pid": 1793, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + } + ], + "get_response": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + }, + { + "name": "label", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_RELEASE_DHCP.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_RELEASE_DHCP.json new file mode 100644 index 0000000..0cb4539 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_RELEASE_DHCP.json @@ -0,0 +1,18 @@ +{ + "name": "INTERFACE_RELEASE_DHCP", + "notes": "E1.37-2", + "manufacturer_id": 0, + "pid": 1780, + "version": 1, + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_RENEW_DHCP.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_RENEW_DHCP.json new file mode 100644 index 0000000..7251fa8 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/INTERFACE_RENEW_DHCP.json @@ -0,0 +1,18 @@ +{ + "name": "INTERFACE_RENEW_DHCP", + "notes": "E1.37-2", + "manufacturer_id": 0, + "pid": 1799, + "version": 1, + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_CURRENT_ADDRESS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_CURRENT_ADDRESS.json new file mode 100644 index 0000000..a6148e0 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_CURRENT_ADDRESS.json @@ -0,0 +1,49 @@ +{ + "name": "IPV4_CURRENT_ADDRESS", + "notes": "E1.37-2", + "manufacturer_id": 0, + "pid": 1797, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + } + ], + "get_response": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + }, + { + "name": "address", + "type": "bytes", + "notes": "All zeros means IPV4_UNCONFIGURED.", + "format": "ipv4" + }, + { + "name": "netmask", + "type": "uint8", + "ranges": [ + { "minimum": 0, "maximum": 32 } + ] + }, + { + "name": "dhcp_status", + "type": "uint8", + "labels": [ + { "name": "INACTIVE", "value": 0 }, + { "name": "ACTIVE", "value": 1 }, + { "name": "UNKNOWN", "value": 2 } + ], + "restrictToLabeled": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_DEFAULT_ROUTE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_DEFAULT_ROUTE.json new file mode 100644 index 0000000..586392e --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_DEFAULT_ROUTE.json @@ -0,0 +1,27 @@ +{ + "name": "IPV4_DEFAULT_ROUTE", + "notes": "E1.37-2", + "manufacturer_id": 0, + "pid": 1802, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + }, + { + "name": "default_route", + "type": "bytes", + "notes": "All zeros means NO_DEFAULT_ROUTE.", + "format": "ipv4" + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_DHCP_MODE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_DHCP_MODE.json new file mode 100644 index 0000000..eb5685f --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_DHCP_MODE.json @@ -0,0 +1,37 @@ +{ + "name": "IPV4_DHCP_MODE", + "notes": "E1.37-2", + "manufacturer_id": 0, + "pid": 1795, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + } + ], + "get_response": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + }, + { + "name": "mode", + "type": "boolean", + "labels": [ + { "name": "Disabled", "value": false }, + { "name": "Enabled", "value": true } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_STATIC_ADDRESS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_STATIC_ADDRESS.json new file mode 100644 index 0000000..c2f9be4 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_STATIC_ADDRESS.json @@ -0,0 +1,41 @@ +{ + "name": "IPV4_STATIC_ADDRESS", + "notes": "E1.37-2", + "manufacturer_id": 0, + "pid": 1798, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + } + ], + "get_response": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + }, + { + "name": "address", + "type": "bytes", + "format": "ipv4" + }, + { + "name": "netmask", + "type": "uint8", + "ranges": [ + { "minimum": 0, "maximum": 32 } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_ZEROCONF_MODE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_ZEROCONF_MODE.json new file mode 100644 index 0000000..e1ba671 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/IPV4_ZEROCONF_MODE.json @@ -0,0 +1,37 @@ +{ + "name": "IPV4_ZEROCONF_MODE", + "notes": "E1.37-2", + "manufacturer_id": 0, + "pid": 1796, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + } + ], + "get_response": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + }, + { + "name": "mode", + "type": "boolean", + "labels": [ + { "name": "Disabled", "value": false }, + { "name": "Enabled", "value": true } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/LIST_INTERFACES.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/LIST_INTERFACES.json new file mode 100644 index 0000000..bb8ad38 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-2/LIST_INTERFACES.json @@ -0,0 +1,32 @@ +{ + "name": "LIST_INTERFACES", + "notes": "E1.37-2", + "manufacturer_id": 0, + "pid": 1792, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "interfaces", + "type": "list", + "itemType": { + "type": "compound", + "subtypes": [ + { + "name": "id", + "type": "uint32", + "ranges": [ + { "minimum": 1, "maximum": 4294967040 } + ] + }, + { + "name": "hardware_type", + "type": "uint16", + "resources": [ "https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml" ] + } + ] + } + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/ADD_TAG.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/ADD_TAG.json new file mode 100644 index 0000000..521f496 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/ADD_TAG.json @@ -0,0 +1,16 @@ +{ + "name": "ADD_TAG", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 1618, + "version": 1, + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "tag", + "type": "string", + "maxLength": 32 + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/CHECK_TAG.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/CHECK_TAG.json new file mode 100644 index 0000000..cb1e97a --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/CHECK_TAG.json @@ -0,0 +1,25 @@ +{ + "name": "CHECK_TAG", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 1620, + "version": 1, + "set_request_subdevice_range": [ "root", "subdevices" ], + "set_request": [ + { + "name": "tag", + "type": "string", + "maxLength": 32 + } + ], + "set_response": [ + { + "name": "status", + "type": "boolean", + "labels": [ + { "name": "Not Present", "value": false }, + { "name": "Present", "value": true } + ] + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/CLEAR_TAGS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/CLEAR_TAGS.json new file mode 100644 index 0000000..487f4f3 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/CLEAR_TAGS.json @@ -0,0 +1,10 @@ +{ + "name": "CLEAR_TAGS", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 1621, + "version": 1, + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/COMMS_STATUS_NSC.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/COMMS_STATUS_NSC.json new file mode 100644 index 0000000..a0831f4 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/COMMS_STATUS_NSC.json @@ -0,0 +1,63 @@ +{ + "name": "COMMS_STATUS_NSC", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 23, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [], + "get_response": [ + { + "name": "supported", + "type": "bitField", + "size": 8, + "bits": [ + { "name": "additive_checksum", "index": 0 }, + { "name": "packet_count", "index": 1 }, + { "name": "most_recent_slot_count", "index": 2 }, + { "name": "min_slot_count", "index": 3 }, + { "name": "max_slot_count", "index": 4 }, + { "name": "error_count", "index": 5 } + ] + }, + { "name": "additive_checksum", "type": "uint32" }, + { + "name": "packet_count", + "type": "uint32", + "labels": [ + { "name": "Not Supported", "value": 4294967295 } + ] + }, + { + "name": "most_recent_slot_count", + "type": "uint16", + "labels": [ + { "name": "Not Supported", "value": 65535 } + ] + }, + { + "name": "min_slot_count", + "type": "uint16", + "labels": [ + { "name": "Not Supported", "value": 65535 } + ] + }, + { + "name": "max_slot_count", + "type": "uint16", + "labels": [ + { "name": "Not Supported", "value": 65535 } + ] + }, + { + "name": "error_count", + "type": "uint32", + "labels": [ + { "name": "Not Supported", "value": 4294967295 } + ] + } + ], + "set_request_subdevice_range": [ "root" ], + "set_request": [], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/DEVICE_INFO_OFFSTAGE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/DEVICE_INFO_OFFSTAGE.json new file mode 100644 index 0000000..be8442d --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/DEVICE_INFO_OFFSTAGE.json @@ -0,0 +1,135 @@ +{ + "name": "DEVICE_INFO_OFFSTAGE", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 212, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "root_personality", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + }, + { + "name": "subdevice", + "type": "uint16", + "labels": [ + { "name": "root", "value": 0 } + ] + }, + { + "name": "subdevice_personality", + "type": "uint8", + "labels": [ + { "name": "root", "value": 0 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { "$ref": "#/get_request/1" }, + { "$ref": "#/get_request/2" }, + { "name": "protocol_major", "type": "uint8" }, + { "name": "protocol_minor", "type": "uint8" }, + { "name": "device_model_id", "type": "uint16" }, + { + "name": "product_category", + "type": "uint16", + "labels": [ + { "name": "NOT_DECLARED", "value": 0 }, + { "name": "FIXTURE", "value": 256 }, + { "name": "FIXTURE_FIXED", "value": 257 }, + { "name": "FIXTURE_MOVING_YOKE", "value": 258 }, + { "name": "FIXTURE_MOVING_MIRROR", "value": 259 }, + { "name": "FIXTURE_OTHER", "value": 511 }, + { "name": "FIXTURE_ACCESSORY", "value": 512 }, + { "name": "FIXTURE_ACCESSORY_COLOR", "value": 513 }, + { "name": "FIXTURE_ACCESSORY_YOKE", "value": 514 }, + { "name": "FIXTURE_ACCESSORY_MIRROR", "value": 515 }, + { "name": "FIXTURE_ACCESSORY_EFFECT", "value": 516 }, + { "name": "FIXTURE_ACCESSORY_BEAM", "value": 517 }, + { "name": "FIXTURE_ACCESSORY_OTHER", "value": 767 }, + { "name": "PROJECTOR", "value": 768 }, + { "name": "PROJECTOR_FIXED", "value": 769 }, + { "name": "PROJECTOR_MOVING_YOKE", "value": 770 }, + { "name": "PROJECTOR_MOVING_MIRROR", "value": 771 }, + { "name": "PROJECTOR_OTHER", "value": 1023 }, + { "name": "ATMOSPHERIC", "value": 1024 }, + { "name": "ATMOSPHERIC_EFFECT", "value": 1025 }, + { "name": "ATMOSPHERIC_PYRO", "value": 1026 }, + { "name": "ATMOSPHERIC_OTHER", "value": 1279 }, + { "name": "DIMMER", "value": 1280 }, + { "name": "DIMMER_AC_INCANDESCENT", "value": 1281 }, + { "name": "DIMMER_AC_FLUORESCENT", "value": 1282 }, + { "name": "DIMMER_AC_COLD_CATHODE", "value": 1283 }, + { "name": "DIMMER_AC_NONDIM", "value": 1284 }, + { "name": "DIMMER_AC_ELV", "value": 1285 }, + { "name": "DIMMER_AC_OTHER", "value": 1286 }, + { "name": "DIMMER_DC_LEVEL", "value": 1287 }, + { "name": "DIMMER_DC_PWM", "value": 1288 }, + { "name": "DIMMER_CS_LED", "value": 1289 }, + { "name": "DIMMER_OTHER", "value": 1535 }, + { "name": "POWER", "value": 1536 }, + { "name": "POWER_CONTROL", "value": 1537 }, + { "name": "POWER_SOURCE", "value": 1538 }, + { "name": "POWER_OTHER", "value": 1791 }, + { "name": "SCENIC", "value": 1792 }, + { "name": "SCENIC_DRIVE", "value": 1793 }, + { "name": "SCENIC_OTHER", "value": 2047 }, + { "name": "DATA", "value": 2048 }, + { "name": "DATA_DISTRIBUTION", "value": 2049 }, + { "name": "DATA_CONVERSION", "value": 2050 }, + { "name": "DATA_OTHER", "value": 2303 }, + { "name": "AV", "value": 2304 }, + { "name": "AV_AUDIO", "value": 2305 }, + { "name": "AV_VIDEO", "value": 2306 }, + { "name": "AV_OTHER", "value": 2559 }, + { "name": "MONITOR", "value": 2560 }, + { "name": "MONITOR_AC_LINE_POWER", "value": 2561 }, + { "name": "MONITOR_DC_POWER", "value": 2562 }, + { "name": "MONITOR_ENVIRONMENTAL", "value": 2563 }, + { "name": "MONITOR_OTHER", "value": 2815 }, + { "name": "CONTROL", "value": 28672 }, + { "name": "CONTROL_CONTROLLER", "value": 28673 }, + { "name": "CONTROL_BACKUP_DEVICE", "value": 28674 }, + { "name": "CONTROL_OTHER", "value": 28927 }, + { "name": "TEST", "value": 28928 }, + { "name": "TEST_EQUIPMENT", "value": 28929 }, + { "name": "TEST_OTHER", "value": 29183 }, + { "name": "OTHER", "value": 32767 } + ] + }, + { "name": "software_version_id", "type": "uint32" }, + { + "name": "dmx_footprint", + "type": "uint16", + "ranges": [ + { "minimum": 0, "maximum": 512 } + ] + }, + { + "name": "current_personality", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + }, + { "name": "personality_count", "type": "uint8" }, + { + "name": "dmx_start_address", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 512 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "No Footprint", "value": 65535 } + ] + }, + { "name": "sub_device_count", "type": "uint16" }, + { "name": "sensor_count", "type": "uint8" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/DEVICE_UNIT_NUMBER.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/DEVICE_UNIT_NUMBER.json new file mode 100644 index 0000000..342e046 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/DEVICE_UNIT_NUMBER.json @@ -0,0 +1,21 @@ +{ + "name": "DEVICE_UNIT_NUMBER", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 1622, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "unit_number", + "type": "uint32", + "labels": [ + { "name": "Unset", "value": 0 } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/DMX_PERSONALITY_ID.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/DMX_PERSONALITY_ID.json new file mode 100644 index 0000000..d5d0dc6 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/DMX_PERSONALITY_ID.json @@ -0,0 +1,22 @@ +{ + "name": "DMX_PERSONALITY_ID", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 226, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "personality", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { "name": "major_id", "type": "uint32" }, + { "name": "minor_id", "type": "uint32" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/FIRMWARE_URL.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/FIRMWARE_URL.json new file mode 100644 index 0000000..0cb65e8 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/FIRMWARE_URL.json @@ -0,0 +1,17 @@ +{ + "name": "FIRMWARE_URL", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 210, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "url", + "type": "string", + "notes": "The spec says that the minimum length is 5, but we shouldn't restrict because that would imply we know what the URL scheme is.", + "format": "url" + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/IDENTIFY_TIMEOUT.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/IDENTIFY_TIMEOUT.json new file mode 100644 index 0000000..7462e6e --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/IDENTIFY_TIMEOUT.json @@ -0,0 +1,23 @@ +{ + "name": "IDENTIFY_TIMEOUT", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 4176, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "timeout", + "type": "uint16", + "units": 21, + "prefixPower": 0, + "labels": [ + { "name": "Disabled", "value": 0 } + ] + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": "get_response", + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/LIST_TAGS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/LIST_TAGS.json new file mode 100644 index 0000000..9f718d2 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/LIST_TAGS.json @@ -0,0 +1,16 @@ +{ + "name": "LIST_TAGS", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 1617, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "tags", + "type": "bytes", + "notes": "NUL-delimited." + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/MANUFACTURER_URL.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/MANUFACTURER_URL.json new file mode 100644 index 0000000..05aae77 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/MANUFACTURER_URL.json @@ -0,0 +1,17 @@ +{ + "name": "MANUFACTURER_URL", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 208, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "url", + "type": "string", + "notes": "The spec says that the minimum length is 5, but we shouldn't restrict because that would imply we know what the URL scheme is.", + "format": "url" + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/METADATA_JSON.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/METADATA_JSON.json new file mode 100644 index 0000000..771db13 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/METADATA_JSON.json @@ -0,0 +1,19 @@ +{ + "name": "METADATA_JSON", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 83, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { "name": "pid", "type": "uint16" } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { + "name": "json", + "type": "string", + "format": "json" + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/METADATA_JSON_URL.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/METADATA_JSON_URL.json new file mode 100644 index 0000000..4b49ace --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/METADATA_JSON_URL.json @@ -0,0 +1,16 @@ +{ + "name": "METADATA_JSON_URL", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 84, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "url", + "type": "string", + "format": "url" + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/METADATA_PARAMETER_VERSION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/METADATA_PARAMETER_VERSION.json new file mode 100644 index 0000000..923e84b --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/METADATA_PARAMETER_VERSION.json @@ -0,0 +1,18 @@ +{ + "name": "METADATA_PARAMETER_VERSION", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 82, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { "name": "pid", "type": "uint16" } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { + "name": "version", + "type": "uint16" + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/POWER_OFF_READY.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/POWER_OFF_READY.json new file mode 100644 index 0000000..ad3e34a --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/POWER_OFF_READY.json @@ -0,0 +1,19 @@ +{ + "name": "POWER_OFF_READY", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 4177, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "state", + "type": "boolean", + "labels": [ + { "name": "Not Ready", "value": false }, + { "name": "Ready", "value": true } + ] + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/PRODUCT_URL.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/PRODUCT_URL.json new file mode 100644 index 0000000..0415439 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/PRODUCT_URL.json @@ -0,0 +1,17 @@ +{ + "name": "PRODUCT_URL", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 209, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "url", + "type": "string", + "notes": "The spec says that the minimum length is 5, but we shouldn't restrict because that would imply we know what the URL scheme is.", + "format": "url" + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/REMOVE_TAG.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/REMOVE_TAG.json new file mode 100644 index 0000000..bec5482 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/REMOVE_TAG.json @@ -0,0 +1,16 @@ +{ + "name": "REMOVE_TAG", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 1619, + "version": 1, + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { + "name": "tag", + "type": "string", + "maxLength": 32 + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/SENSOR_TYPE_CUSTOM.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/SENSOR_TYPE_CUSTOM.json new file mode 100644 index 0000000..3f0fd0d --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/SENSOR_TYPE_CUSTOM.json @@ -0,0 +1,25 @@ +{ + "name": "SENSOR_TYPE_CUSTOM", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 528, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "sensor_type", + "type": "uint8", + "ranges": [ + { "minimum": 128, "maximum": 255 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { + "name": "label", + "type": "string", + "maxLength": 32 + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/SENSOR_UNIT_CUSTOM.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/SENSOR_UNIT_CUSTOM.json new file mode 100644 index 0000000..1db4c71 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/SENSOR_UNIT_CUSTOM.json @@ -0,0 +1,25 @@ +{ + "name": "SENSOR_UNIT_CUSTOM", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 529, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "sensor_unit", + "type": "uint8", + "ranges": [ + { "minimum": 128, "maximum": 255 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { + "name": "label", + "type": "string", + "maxLength": 32 + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/SERIAL_NUMBER.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/SERIAL_NUMBER.json new file mode 100644 index 0000000..2873a47 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/SERIAL_NUMBER.json @@ -0,0 +1,16 @@ +{ + "name": "SERIAL_NUMBER", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 211, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "serial_number", + "type": "string", + "maxLength": 231 + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/SHIPPING_LOCK.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/SHIPPING_LOCK.json new file mode 100644 index 0000000..79f7003 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/SHIPPING_LOCK.json @@ -0,0 +1,35 @@ +{ + "name": "SHIPPING_LOCK", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 1616, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [], + "get_response": [ + { + "name": "lock_state", + "type": "uint8", + "labels": [ + { "name": "UNLOCKED", "value": 0 }, + { "name": "LOCKED", "value": 1 }, + { "name": "PARTIALLY_LOCKED", "value": 2 } + ], + "restrictToLabeled": true + } + ], + "set_request_subdevice_range": [ "root" ], + "set_request": [ + { + "name": "lock_state", + "type": "uint8", + "notes": "The list here is more restrictive than for getting the lock state. Do we want to add states and maybe descriptions?", + "labels": [ + { "name": "Unlocked", "value": 0 }, + { "name": "Locked", "value": 1 } + ], + "restrictToLabeled": true + } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/TEST_DATA.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/TEST_DATA.json new file mode 100644 index 0000000..71d2a4a --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-5/TEST_DATA.json @@ -0,0 +1,33 @@ +{ + "name": "TEST_DATA", + "notes": "E1.37-5", + "manufacturer_id": 0, + "pid": 22, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "pattern_length", + "type": "uint16", + "ranges": [ + { "minimum": 0, "maximum": 4096 } + ] + } + ], + "get_response": [ + { + "name": "pattern_data", + "type": "bytes", + "maxLength": 4096 + } + ], + "set_request_subdevice_range": [ "root", "subdevices" ], + "set_request": [ + { + "name": "loopback_data", + "type": "bytes", + "maxLength": 231 + } + ], + "set_response": "set_request" +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/BACKGROUND_DISCOVERY.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/BACKGROUND_DISCOVERY.json new file mode 100644 index 0000000..c762a78 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/BACKGROUND_DISCOVERY.json @@ -0,0 +1,39 @@ +{ + "name": "BACKGROUND_DISCOVERY", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2312, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { "name": "enabled", "type": "boolean" } + ], + "set_request_subdevice_range": [ "root" ], + "set_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "BROADCAST", "value": 65535 } + ] + }, + { "$ref": "#/get_response/1" } + ], + "set_response": [ + { "$ref": "#/set_request/0" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/BACKGROUND_QUEUED_STATUS_POLICY.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/BACKGROUND_QUEUED_STATUS_POLICY.json new file mode 100644 index 0000000..4baa465 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/BACKGROUND_QUEUED_STATUS_POLICY.json @@ -0,0 +1,32 @@ +{ + "name": "BACKGROUND_QUEUED_STATUS_POLICY", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2318, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { + "name": "policy_setting", + "type": "uint8", + "notes": "See \"Table 7-3: Control Field\" in ANSI E1.20-202x. The labeled values are just informative, but this contradicts with the spec (E1.37-7) saying \"must support this minimum set\".", + "labels": [ + { "name": "STATUS_NONE", "value": 0 }, + { "name": "STATUS_ADVISORY", "value": 1 }, + { "name": "STATUS_WARNING", "value": 2 }, + { "name": "STATUS_ERROR", "value": 3 } + ] + }, + { + "name": "policy_setting_count", + "type": "uint8", + "notes": "Breaking with other message definitions (and this is not mentioned in the spec), the policy setting value starts at 0, unlike others which start at 1. This means that the maximum value is 254 since the count can be at most 255." + } + ], + "set_request_subdevice_range": [ "root", "subdevices", "broadcast" ], + "set_request": [ + { "$ref": "#/get_response/0" } + ], + "set_response": [] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION.json new file mode 100644 index 0000000..92e17a9 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION.json @@ -0,0 +1,29 @@ +{ + "name": "BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2319, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "policy", + "type": "uint8", + "labels": [ + { "name": "Status Type None", "value": 0 }, + { "name": "Status Type Advisory and higher", "value": 1 }, + { "name": "Status Type Warning and higher", "value": 2 }, + { "name": "Status Type Error", "value": 3 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { + "name": "description", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/BINDING_CONTROL_FIELDS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/BINDING_CONTROL_FIELDS.json new file mode 100644 index 0000000..d5634a4 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/BINDING_CONTROL_FIELDS.json @@ -0,0 +1,37 @@ +{ + "name": "BINDING_CONTROL_FIELDS", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2317, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 } + ] + }, + { + "name": "uid", + "type": "bytes", + "format": "uid" + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { "$ref": "#/get_request/1" }, + { + "name": "control", + "type": "uint16", + "notes": "See \"Table 7-3: Control Field\" in ANSI E1.20-202x." + }, + { + "name": "binding_uid", + "type": "bytes", + "notes": "All zeros means no Binding UID present in the DISC_MUTE response.", + "format": "uid" + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/DISCOVERY_STATE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/DISCOVERY_STATE.json new file mode 100644 index 0000000..b2037c1 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/DISCOVERY_STATE.json @@ -0,0 +1,74 @@ +{ + "name": "DISCOVERY_STATE", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2311, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { + "name": "device_count", + "type": "uint16", + "ranges": [ + { "minimum": 0, "maximum": 63999 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "DISCOVERY_COUNT_INCOMPLETE", "value": 0 }, + { "name": "DISCOVERY_COUNT_UNKNOWN", "value": 65535 } + ] + }, + { + "name": "state", + "type": "uint8", + "ranges": [ + { "minimum": 0, "maximum": 223 } + ], + "labels": [ + { "name": "INCOMPLETE", "value": 0 }, + { "name": "INCREMENTAL", "value": 1 }, + { "name": "FULL", "value": 2 }, + { "name": "NOT_ACTIVE", "value": 3 } + ] + } + ], + "set_request_subdevice_range": [ "root" ], + "set_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "BROADCAST", "value": 65535 } + ] + }, + { + "name": "state", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 223 } + ], + "labels": [ + { "name": "INCREMENTAL", "value": 1 }, + { "name": "FULL", "value": 2 }, + { "name": "NOT_ACTIVE", "value": 3 } + ] + } + ], + "set_response": [ + { "$ref": "#/set_request/0" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_LABEL.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_LABEL.json new file mode 100644 index 0000000..0f49f88 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_LABEL.json @@ -0,0 +1,44 @@ +{ + "name": "ENDPOINT_LABEL", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2309, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { + "name": "label", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ], + "set_request_subdevice_range": [ "root" ], + "set_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "BROADCAST", "value": 65535 } + ] + }, + { "$ref": "#/get_response/1" } + ], + "set_response": [ + { "$ref": "#/set_request/0" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_LIST.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_LIST.json new file mode 100644 index 0000000..6c34502 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_LIST.json @@ -0,0 +1,37 @@ +{ + "name": "ENDPOINT_LIST", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2304, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [], + "get_response": [ + { "name": "list_change_number", "type": "uint32" }, + { + "name": "endpoints", + "type": "list", + "itemType": { + "type": "compound", + "subtypes": [ + { + "name": "id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 } + ] + }, + { + "name": "type", + "type": "uint8", + "labels": [ + { "name": "VIRTUAL", "value": 0 }, + { "name": "PHYSICAL", "value": 1 } + ], + "restrictToLabeled": true + } + ] + } + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_LIST_CHANGE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_LIST_CHANGE.json new file mode 100644 index 0000000..8f6720e --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_LIST_CHANGE.json @@ -0,0 +1,12 @@ +{ + "name": "ENDPOINT_LIST_CHANGE", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2305, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [], + "get_response": [ + { "name": "list_change_number", "type": "uint32" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_MODE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_MODE.json new file mode 100644 index 0000000..9c83db9 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_MODE.json @@ -0,0 +1,48 @@ +{ + "name": "ENDPOINT_MODE", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2308, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { + "name": "mode", + "type": "uint8", + "labels": [ + { "name": "Disabled", "value": 0 }, + { "name": "Input", "value": 1 }, + { "name": "Output", "value": 2 } + ], + "restrictToLabeled": true + } + ], + "set_request_subdevice_range": [ "root" ], + "set_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "BROADCAST", "value": 65535 } + ] + }, + { "$ref": "#/get_response/1" } + ], + "set_response": [ + { "$ref": "#/set_request/0" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_RESPONDERS.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_RESPONDERS.json new file mode 100644 index 0000000..0437b36 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_RESPONDERS.json @@ -0,0 +1,30 @@ +{ + "name": "ENDPOINT_RESPONDERS", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2315, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { "name": "list_change_number", "type": "uint32" }, + { + "name": "uids", + "type": "list", + "itemType": { + "name": "uid", + "type": "bytes", + "format": "uid" + } + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_RESPONDER_LIST_CHANGE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_RESPONDER_LIST_CHANGE.json new file mode 100644 index 0000000..c7cee97 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_RESPONDER_LIST_CHANGE.json @@ -0,0 +1,21 @@ +{ + "name": "ENDPOINT_RESPONDER_LIST_CHANGE", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2316, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { "name": "list_change_number", "type": "uint32" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_TIMING.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_TIMING.json new file mode 100644 index 0000000..2f8c9c0 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_TIMING.json @@ -0,0 +1,46 @@ +{ + "name": "ENDPOINT_TIMING", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2313, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { + "name": "setting", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + }, + { "name": "setting_count", "type": "uint8" } + ], + "set_request_subdevice_range": [ "root" ], + "set_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "BROADCAST", "value": 65535 } + ] + }, + { "$ref": "#/get_response/1" } + ], + "set_response": [ + { "$ref": "#/set_request/0" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_TIMING_DESCRIPTION.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_TIMING_DESCRIPTION.json new file mode 100644 index 0000000..e1cbb6b --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_TIMING_DESCRIPTION.json @@ -0,0 +1,26 @@ +{ + "name": "ENDPOINT_TIMING_DESCRIPTION", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2314, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "setting", + "type": "uint8", + "ranges": [ + { "minimum": 1, "maximum": 255 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { + "name": "description", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_TO_UNIVERSE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_TO_UNIVERSE.json new file mode 100644 index 0000000..e8db959 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/ENDPOINT_TO_UNIVERSE.json @@ -0,0 +1,59 @@ +{ + "name": "ENDPOINT_TO_UNIVERSE", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2307, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { + "name": "universe", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "Unpatched", "value": 0 }, + { "name": "Composite", "value": 65535 } + ] + } + ], + "set_request_subdevice_range": [ "root" ], + "set_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "BROADCAST", "value": 65535 } + ] + }, + { + "name": "universe", + "type": "uint16", + "ranges": [ + { "minimum": 0, "maximum": 63999 } + ], + "labels": [ + { "name": "Unpatched", "value": 0 } + ] + } + ], + "set_response": [ + { "$ref": "#/set_request/0" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/IDENTIFY_ENDPOINT.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/IDENTIFY_ENDPOINT.json new file mode 100644 index 0000000..16eed74 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/IDENTIFY_ENDPOINT.json @@ -0,0 +1,46 @@ +{ + "name": "IDENTIFY_ENDPOINT", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2306, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { + "name": "identify_state", + "type": "boolean", + "labels": [ + { "name": "Off", "value": false }, + { "name": "On", "value": true } + ] + } + ], + "set_request_subdevice_range": [ "root" ], + "set_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "BROADCAST", "value": 65535 } + ] + }, + { "$ref": "#/get_response/1" } + ], + "set_response": [ + { "$ref": "#/set_request/0" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/RDM_TRAFFIC_ENABLE.json b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/RDM_TRAFFIC_ENABLE.json new file mode 100644 index 0000000..6b091dd --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/Defines/e1.37-7/RDM_TRAFFIC_ENABLE.json @@ -0,0 +1,39 @@ +{ + "name": "RDM_TRAFFIC_ENABLE", + "notes": "E1.37-7", + "manufacturer_id": 0, + "pid": 2310, + "version": 1, + "get_request_subdevice_range": [ "root" ], + "get_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 } + ] + } + ], + "get_response": [ + { "$ref": "#/get_request/0" }, + { "name": "rdm_enabled", "type": "boolean" } + ], + "set_request_subdevice_range": [ "root" ], + "set_request": [ + { + "name": "endpoint_id", + "type": "uint16", + "ranges": [ + { "minimum": 1, "maximum": 63999 }, + { "minimum": 65535, "maximum": 65535 } + ], + "labels": [ + { "name": "BROADCAST", "value": 65535 } + ] + }, + { "$ref": "#/get_response/1" } + ], + "set_response": [ + { "$ref": "#/set_request/0" } + ] +} diff --git a/RDMSharp/Resources/JSON-Defines/1.0.0/schema.json b/RDMSharp/Resources/JSON-Defines/1.0.0/schema.json new file mode 100644 index 0000000..f8fa984 --- /dev/null +++ b/RDMSharp/Resources/JSON-Defines/1.0.0/schema.json @@ -0,0 +1,599 @@ +{ + "$id": "https://www.esta.org/e1.37-5/schemas/1.0.0/schema.json", + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Parameter Message", + "description": "The schema for the Parameter Metadata Language from Section 5 of E1.37-5. This schema is subject to change.", + "type": "object", + "$ref": "#/$defs/commonPropertiesForNamed", + "properties": { + "manufacturer_id": { + "$comment": "Manufacturer IDs are assigned by ESTA and are commonly expressed in hexadecimal. Users may expect to see these values in the UI as hexadecimal.", + "title": "Manufacturer ID", + "description": "The Manufacturer ID.", + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "device_model_id": { + "$comment": "The Device Model ID is a 16-bit value determined by the manufacturer. Users may expect to see these values in the UI as hexadecimal.", + "title": "Device Model ID", + "description": "The Device Model ID.", + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "software_version_id": { + "$comment": "The Software Version ID is a 32-bit value determined by the manufacturer.", + "title": "Software Version ID", + "description": "The Software Version ID.", + "type": "integer", + "minimum": 0, + "maximum": 4294967295 + }, + "pid": { + "title": "PID", + "description": "The parameter ID.", + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "version": { + "title": "Version", + "description": "The parameter descriptor version.", + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "get_request_subdevice_range": { + "$comment": "'subdevicesForRequests' already contains a title and description", + "description": "Absence implies a default value of [\"root\"].", + "$ref": "#/$defs/subdevicesForRequests", + "default": [ "root" ] + }, + "get_request": { + "$comment": "'command' already contains a description", + "title": "GET Command", + "$ref": "#/$defs/command" + }, + "get_response_subdevice_range": { + "$comment": "'subdevicesForResponses' already contains a title and description", + "description": "Absence implies a default value of [\"match\"].", + "$ref": "#/$defs/subdevicesForResponses", + "default": [ "match" ] + }, + "get_response": { + "$comment": "'command' already contains a description", + "title": "GET Command Response", + "$ref": "#/$defs/command" + }, + "set_request_subdevice_range": { + "$comment": "'subdevicesForRequests' already contains a title and description", + "description": "Absence implies a default value of [\"root\"].", + "$ref": "#/$defs/subdevicesForRequests", + "default": [ "root" ] + }, + "set_request": { + "$comment": "'command' already contains a description", + "title": "SET Command", + "$ref": "#/$defs/command" + }, + "set_response_subdevice_range": { + "$comment": "'subdevicesForResponses' already contains a title and description", + "description": "Absence implies a default value of [\"match\"].", + "$ref": "#/$defs/subdevicesForResponses", + "default": [ "match" ] + }, + "set_response": { + "$comment": "'command' already contains a description", + "title": "SET Command Response", + "$ref": "#/$defs/command" + } + }, + "unevaluatedProperties": false, + "required": [ "manufacturer_id", "pid", "version" ], + "dependentRequired": { + "get_request": [ "get_response" ], + "get_response": [ "get_request" ], + "set_request": [ "set_response" ], + "set_response": [ "set_request" ] + }, + "$defs": { + "bit": { + "title": "Bit", + "description": "One bit in a bit field.", + "type": "object", + "$ref": "#/$defs/commonPropertiesForNamed", + "properties": { + "index": { + "title": "Index", + "description": "Zero-based index of this bit.", + "type": "integer", + "minimum": 0 + }, + "reserved": { + "title": "Reserved", + "description": "Indicates that this bit is unused or reserved. Note that this value does not need to be specified for absent bits; they are already assumed to be reserved.", + "type": "boolean" + }, + "valueIfReserved": { + "title": "Value If Reserved", + "description": "The assumed value when the bit is marked as reserved. Absence implies a default value of false.", + "type": "boolean", + "default": false + } + }, + "unevaluatedProperties": false, + "required": [ "index" ] + }, + "bitFieldType": { + "title": "Bit Field Type", + "description": "A bit field, a collection of 'bit' items. The \"size\" field is used to specify the number of bits in this bit field, a multiple of 8. It is an error if the size is less than the number of defined bits. Bits that are not specified are assumed to be reserved, having a value equal to the \"valueForUnspecified\" value.", + "type": "object", + "$ref": "#/$defs/commonPropertiesForNamed", + "properties": { + "type": { "const": "bitField" }, + "bits": { + "title": "Bits", + "description": "A list of the bits in the bit field.", + "type": "array", + "items": { "$ref": "#/$defs/bit" }, + "uniqueItems": true + }, + "size": { + "title": "Size", + "description": "The size, in multiples-of-8 bits, of this bit field. It is an error if the size is less than the number of defined bits.", + "type": "integer", + "minimum": 0, + "multipleOf": 8 + }, + "valueForUnspecified": { + "title": "Value for Unspecified", + "description": "The default value to use for any unspecified bits. Absence implies a default value of false.", + "type": "boolean", + "default": false + } + }, + "required": [ "type", "size", "bits" ] + }, + "booleanType": { + "title": "Boolean Type", + "description": "A Boolean value. This corresponds to the intent of DS_BOOLEAN in \"Table A-15: Data Type Defines\" of the E1.20-2010 specification, a 1-byte zero-or-one value.", + "type": "object", + "$ref": "#/$defs/commonPropertiesForNamed", + "properties": { + "type": { "const": "boolean" }, + "labels": { + "title": "Labels", + "description": "A list of labels that name special values.", + "type": "array", + "items": { "$ref": "#/$defs/labeledBoolean" }, + "uniqueItems": true, + "maxItems": 2 + } + }, + "required": [ "type" ] + }, + "bytesType": { + "title": "Bytes Type", + "description": "An array of bytes. The minimum and maximum length properties are not required, but it is a good idea to specify their values for unknown bytes types. This corresponds to the intent of DS_UNSIGNED_BYTE in \"Table A-15: Data Type Defines\" of the E1.20-2010 specification.", + "type": "object", + "$ref": "#/$defs/commonPropertiesForNamed", + "properties": { + "type": { "const": "bytes" }, + "format": { + "title": "Interpretation Format", + "description": "This field describes how to interpret the value. It can be one of the bytes types defined in \"Table A-15: Data Type Defines\" of the E1.20-2010 specification (or other add-on specifications), or it can be something manufacturer-specific. Be aware, however, that anything not defined here may not be understood by a controller or UI. The known bytes types include: ipv4 (4 bytes), ipv6 (16 bytes), mac-address (6 bytes), uid (6 bytes), and uuid (16 bytes).", + "type": "string" + }, + "minLength": { + "title": "Minimum Length", + "description": "The minimum bytes length. Care must be taken to make sure this doesn't contradict any \"maxLength\" value. It is an error if there is a contradiction.", + "type": "integer", + "minimum": 0 + }, + "maxLength": { + "title": "Maximum Length", + "description": "The maximum bytes length. Care must be taken to make sure this doesn't contradict any \"minLength\" value. It is an error if there is a contradiction. If a responder requires a controller to limit the number of bytes sent, then this value should be set.", + "type": "integer", + "minimum": 0 + } + }, + "required": [ "type" ] + }, + "command": { + "$comment": "The title is specific to where this used, and so no title is defined here", + "description": "The contents of an RDM command: 1. a collection of 'field' items, each a simple or compound type, 2. a single 'field' item, or 3. a duplicate command.", + "oneOf": [ + { + "title": "List of Fields", + "description": "The command consists of zero or more fields.", + "type": "array", + "items": { + "$ref": "#/$defs/oneOfTypes", + "unevaluatedProperties": false + }, + "uniqueItems": true + }, + { + "title": "Single Field", + "description": "The command consists of a single field.", + "$ref": "#/$defs/oneOfTypes", + "unevaluatedProperties": false + }, + { + "title": "Command Duplicate", + "description": "Indicates that a command is a duplicate of one of the other commands. Using this feature can potentially save space. It is an error if the command refers to itself.", + "enum": [ + "get_request", + "get_response", + "set_request", + "set_response", + "different_pid" + ] + } + ] + }, + "commonPropertiesForNamed": { + "$comment": "Defines a set of properties common to everything having a name", + "properties": { + "name": { + "title": "Name", + "description": "The object name. If this is not intended for UI display, then a displayable name can be added with \"displayName\". This property can, for example, be used as the key for lookup into a table of localized display names.", + "type": "string", + "minLength": 1 + }, + "displayName": { + "title": "Display Name", + "description": "An optional name for UI display. This might be used, for example, as the fallback or default display name if, say, a localized name isn't specified or found via the \"name\" property.", + "type": "string", + "minLength": 1 + }, + "notes": { + "title": "Notes", + "description": "Contains any notes about this object.", + "type": "string" + }, + "resources": { + "title": "List of Resources", + "description": "Informative URLs pointing to a specification or more information for this field type.", + "type": "array", + "items": { + "type": "string", + "format": "uri-reference" + } + } + } + }, + "compoundType": { + "title": "Compound Type", + "description": "Defines a compound type, a type used to combine other types. This is useful for including in lists. This corresponds to the intent of DS_GROUP in \"Table A-15: Data Type Defines\" of the E1.20-2010 specification.", + "type": "object", + "$ref": "#/$defs/commonPropertiesForNamed", + "properties": { + "type": { "const": "compound" }, + "subtypes": { + "title": "Subtypes", + "description": "A list of types composing this compound type.", + "type": "array", + "items": { + "$ref": "#/$defs/oneOfTypes", + "unevaluatedProperties": false + } + } + }, + "required": [ "type", "subtypes" ] + }, + "integerType": { + "title": "Integer Type", + "description": "A signed or unsigned integer, can have an optional prefix, unit, and range. This corresponds to the intent of any of the integer types in \"Table A-15: Data Type Defines\" of the E1.20-2010 specification.", + "type": "object", + "$ref": "#/$defs/commonPropertiesForNamed", + "properties": { + "type": { + "enum": [ + "int8", + "int16", + "int32", + "int64", + "int128", + "uint8", + "uint16", + "uint32", + "uint64", + "uint128" + ] + }, + "labels": { + "title": "Labels", + "description": "A list of labels that name special values.", + "type": "array", + "items": { "$ref": "#/$defs/labeledInteger" }, + "uniqueItems": true + }, + "restrictToLabeled": { + "title": "Restrict to Labeled", + "description": "Whether to restrict the allowed values to those that have labels. This is useful to not have to additionally specify a set of ranges. If this is set to \"true\" then \"ranges\" should not be specified.", + "type": "boolean" + }, + "ranges": { + "title": "Ranges", + "description": "A list of possible ranges for the value. The complete range is the union of all the ranges. This should not be specified if \"restrictToLabeled\" is set to 'true'.", + "type": "array", + "items": { "$ref": "#/$defs/range" }, + "uniqueItems": true + }, + "units": { + "title": "Units", + "description": "The units type, defined in Table A-13 of E1.20-2010.", + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "prefixPower": { + "title": "Prefix Power", + "description": "The power of 10 to be used as the prefix for the value. For example, -2 is used to represent 10^(-2) or the prefix centi-. Absence implies a default value of 0.", + "type": "integer", + "default": 0 + }, + "prefixBase": { + "title": "Prefix Base", + "description": "The base of the prefix. For example, to express \"kilo\", specify prefixBase=10 and prefixPower=3, and to express \"kibi\", specify prefixBase=2 and prefixPower=10 or prefixBase=1024 and prefixPower=1. Absence implies a default value of 10.", + "type": "integer", + "default": 10 + } + }, + "required": [ "type" ] + }, + "labeledBoolean": { + "title": "Labeled Boolean", + "description": "Associates a name to a Boolean value.", + "type": "object", + "$ref": "#/$defs/commonPropertiesForNamed", + "properties": { + "value": { + "title": "Value", + "description": "The labeled value", + "type": "boolean" + } + }, + "unevaluatedProperties": false, + "required": [ "name", "value" ] + }, + "labeledInteger": { + "title": "Labeled Integer", + "description": "Associates a name to an integer value.", + "type": "object", + "$ref": "#/$defs/commonPropertiesForNamed", + "properties": { + "value": { + "title": "Value", + "description": "The labeled value", + "type": "integer" + } + }, + "unevaluatedProperties": false, + "required": [ "name", "value" ] + }, + "listType": { + "title": "List Type", + "description": "A list of objects all having the same type.", + "$comment": "The names \"minItems\" and \"maxItems\" were chosen because those match the validation keywords for arrays in the JSON schema spec", + "type": "object", + "$ref": "#/$defs/commonPropertiesForNamed", + "properties": { + "type": { "const": "list" }, + "itemType": { + "title": "Item Type", + "description": "The type of each item in the list.", + "$ref": "#/$defs/oneOfTypes", + "unevaluatedProperties": false + }, + "minItems": { + "title": "Minimum List Size", + "description": "The minimum list size.", + "type": "integer", + "minimum": 0 + }, + "maxItems": { + "title": "Maximum List Size", + "description": "The maximum list size.", + "type": "integer", + "minimum": 0 + } + }, + "required": [ "type", "itemType" ] + }, + "oneOfTypes": { + "$comment": "One of any of the types. This provides a single location to keep the list. None of the types here specify \"unevaluatedProperties\", so if extra properties are to be disallowed, then that must be specified by the referencer of this schema. This will make sorting through any errors easier", + "oneOf": [ + { "$ref": "#/$defs/bitFieldType" }, + { "$ref": "#/$defs/booleanType" }, + { "$ref": "#/$defs/bytesType" }, + { "$ref": "#/$defs/compoundType" }, + { "$ref": "#/$defs/integerType" }, + { "$ref": "#/$defs/listType" }, + { "$ref": "#/$defs/pdEnvelopeType" }, + { "$ref": "#/$defs/refType" }, + { "$ref": "#/$defs/stringType" } + ] + }, + "pdEnvelopeType": { + "title": "PD Envelope Type", + "description": "Contains a length/data pair for one Parameter Data item, where the length is an unsigned 8-bit value and the data has 'length' bytes. This exists to provide a schema definition for the 'envelope' of a PDL/PD pair.", + "type": "object", + "$ref": "#/$defs/commonPropertiesForNamed", + "properties": { + "type": { "const": "pdEnvelope" }, + "length": { + "title": "Data Length", + "description": "The data length can be optionally specified.", + "type": "integer", + "minimum": 0, + "maximum": 255 + } + }, + "required": [ "type" ] + }, + "range": { + "title": "Range", + "description": "Defines an inclusive range of numbers. If one of the bounds is undefined then it is assumed to be the bound appropriate for the type.", + "type": "object", + "properties": { + "minimum": { + "title": "Minimum", + "description": "The lower bound, inclusive.", + "type": "integer" + }, + "maximum": { + "title": "Maximum", + "description": "The upper bound, inclusive.", + "type": "integer" + } + }, + "additionalProperties": false + }, + "refType": { + "title": "Reference Type", + "description": "Specifies a reference to another value, a URI whose fragment part, if present, is a JSON Pointer. See [URI Syntax](https://www.rfc-editor.org/rfc/rfc3986.html) and [JSON Pointer](https://www.rfc-editor.org/rfc/rfc6901.html). It is an error if this does not point to an object having one of the types in \"#/$defs/oneOfTypes\", or if there is a circular reference. Any common properties defined in this field will override any defined by the referenced field.", + "type": "object", + "$ref": "#/$defs/commonPropertiesForNamed", + "properties": { + "$ref": { + "title": "Reference", + "description": "Points to a resource, a URI.", + "type": "string", + "format": "uri-reference" + } + }, + "additionalProperties": false, + "required": [ "$ref" ] + }, + "stringType": { + "title": "String Type", + "description": "A UTF-8-encoded string having a possibly bounded size. Implementations may need to use either a NUL terminator or another \"length\" field for multi-field messages where a string is followed by another field, so that its boundary can be determined. This corresponds to the intent of DS_STRING in \"Table A-15: Data Type Defines\" of the E1.20-2010 specification. Characters are defined by the [JSON specification](https://www.rfc-editor.org/rfc/rfc8259.html) (see [Section 7: Strings](https://www.rfc-editor.org/rfc/rfc8259.html#section-7) and [Section 8: String and Character Issues](https://www.rfc-editor.org/rfc/rfc8259.html#section-8)). Note that characters are either encoded directly in UTF-8 or escaped using the scheme described by the specification.", + "type": "object", + "$ref": "#/$defs/commonPropertiesForNamed", + "properties": { + "type": { "const": "string" }, + "format": { + "title": "Interpretation Format", + "description": "This field describes how to interpret the string value. It can be one of the string types defined in \"Table A-15: Data Type Defines\" of the E1.20-2010 specification (or other add-on specifications), one of the defined formats from the [JSON Schema Validation specification](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.7.3), or it can be something manufacturer-specific. It is suggested that a URI or other unique naming convention be used to uniquely identify these. Be aware, however, that anything not defined here may not be understood by a controller or UI. The known string types from E1.20-2010 (and add-ons) include: \"hostname\" (https://www.rfc-editor.org/rfc/rfc1123.html#section-2, https://www.rfc-editor.org/rfc/rfc3696.html#section-2, https://www.rfc-editor.org/rfc/rfc5890.html), \"json\" (https://www.rfc-editor.org/rfc/rfc8259.html), \"string\", and \"url\" (the intent of DS_URL in \"Table A-15\") (https://www.rfc-editor.org/rfc/rfc3986.html, https://www.rfc-editor.org/rfc/rfc1738.html).", + "type": "string" + }, + "pattern": { + "title": "Pattern", + "description": "An [ECMA-262 regular expression](https://www.ecma-international.org/publications/standards/Ecma-262.htm) that can be used to validate the contents of this field. They're helpful for assisting a controller or UI do message validation. It's not necessary to provide a pattern for known \"format\" types. Note that care must be taken to make sure that patterns don't contradict any \"minLength\" and \"maxLength\" values. It is an error if there is a contradiction. As well, if there are maximum or minimum sizes, it is suggested that an instance makes use of the \"minLength\" and \"maxLength\" sizes in order to support those UIs that don't support regexes.", + "type": "string", + "format": "regex" + }, + "minLength": { + "title": "Minimum Length", + "description": "The minimum string length, in characters as defined by [JSON](https://www.rfc-editor.org/rfc/rfc8259.html). Care must be taken to make sure this doesn't contradict any \"pattern\" or \"maxLength\" values. It is an error if there is a contradiction. If there are maximum or minimum sizes, it is suggested that an instance makes use of the \"minLength\" and \"maxLength\" sizes in order to support those UIs that don't support regexes.", + "type": "integer", + "minimum": 0 + }, + "maxLength": { + "title": "Maximum Length", + "description": "The maximum string length, in characters as defined by [JSON](https://www.rfc-editor.org/rfc/rfc8259.html). Care must be taken to make sure this doesn't contradict any \"pattern\" or \"minLength\" values. It is an error if there is a contradiction. If there are maximum or minimum sizes, it is suggested that an instance makes use of the \"minLength\" and \"maxLength\" sizes in order to support those UIs that don't support regexes.", + "type": "integer", + "minimum": 0 + }, + "minBytes": { + "title": "Minimum Length in Bytes", + "description": "The minimum UTF-8-encoded length in bytes. In the case that the number of characters in the string is different from the number of bytes after UTF-8 encoding, we may need to specify a minimum encoded length.", + "type": "integer", + "minimum": 0 + }, + "maxBytes": { + "title": "Maximum Length in Bytes", + "description": "The maximum UTF-8-encoded length in bytes. In the case that the number of characters in the string is different from the number of bytes after UTF-8 encoding, we may need to specify a maximum encoded length. If a responder requires a controller to limit the number of bytes sent, then this value should be set.", + "type": "integer", + "minimum": 0 + }, + "restrictToASCII": { + "title": "Restrict to ASCII", + "description": "Indicates whether the string contents should be restricted to US-ASCII.", + "type": "boolean" + } + }, + "required": [ "type" ] + }, + "subdeviceType": { + "title": "Subdevice Type", + "description": "A subdevice value. It is a 16-bit integral type and its range includes the values specified by the E1.20-2010 specification (0x0001-0x0200). It does not include the root value (0) or special all-call value (65535).", + "type": "integer", + "minimum": 1, + "maximum": 512 + }, + "subdeviceRange": { + "title": "Subdevice Range", + "description": "Defines a range of subdevices, not including the root or the special all-call value. The complete range is the union of all the ranges in the subdevice array.", + "type": "object", + "properties": { + "minimum": { + "$comment": "'subdeviceType' already contains a title and description", + "title": "Minimum", + "description": "The lower bound, inclusive.", + "$ref": "#/$defs/subdeviceType" + }, + "maximum": { + "$comment": "'subdeviceType' already contains a title and description", + "title": "Maximum", + "description": "The upper bound, inclusive.", + "$ref": "#/$defs/subdeviceType" + } + }, + "required": [ "minimum", "maximum" ], + "additionalProperties": false + }, + "subdeviceValue": { + "title": "Subdevice Value", + "description": "Defines a single subdevice or range of subdevices. Note that a \"subdevice\" here means any valid subdevice that isn't \"root\" or \"broadcast\".", + "anyOf": [ + { "$ref": "#/$defs/subdeviceRange" }, + { "$ref": "#/$defs/subdeviceType" } + ] + }, + "subdevicesForRequests": { + "title": "Subdevices in a Request", + "description": "Acceptable values for the subdevice in a GET or SET command. An empty list means allow nothing.", + "type": "array", + "items": { + "anyOf": [ + { + "enum": [ + "root", + "subdevices", + "broadcast" + ] + }, + { + "$ref": "#/$defs/subdeviceValue" + } + ] + }, + "uniqueItems": true + }, + "subdevicesForResponses": { + "title": "Subdevices in a Response", + "description": "Acceptable values for the subdevice in a GET_RESPONSE or SET_RESPONSE. An empty list means allow nothing.", + "type": "array", + "items": { + "anyOf": [ + { + "enum": [ + "root", + "subdevices", + "broadcast", + "match" + ] + }, + { + "$ref": "#/$defs/subdeviceValue" + } + ] + }, + "uniqueItems": true + } + } +} diff --git a/RDMSharpTests/Devices/Mock/MockGeneratedDevice1.cs b/RDMSharpTests/Devices/Mock/MockGeneratedDevice1.cs index 2efbd79..a0c9cea 100644 --- a/RDMSharpTests/Devices/Mock/MockGeneratedDevice1.cs +++ b/RDMSharpTests/Devices/Mock/MockGeneratedDevice1.cs @@ -50,8 +50,8 @@ internal sealed class MockGeneratedDevice1 : AbstractMockGeneratedDevice public MockGeneratedDevice1(UID uid) : base(uid, [ERDM_Parameter.IDENTIFY_DEVICE, ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL], "Dummy Manufacturer 9FFF") { this.DeviceLabel = "Dummy Device 1"; - this.TrySetParameter(ERDM_Parameter.IDENTIFY_DEVICE, false); - this.TrySetParameter(ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL, $"Dummy Software"); + this.trySetParameter(ERDM_Parameter.IDENTIFY_DEVICE, false); + this.trySetParameter(ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL, $"Dummy Software"); } private class MockSensorTemp : Sensor diff --git a/RDMSharpTests/Devices/TestRDMSendReceive.cs b/RDMSharpTests/Devices/TestRDMSendReceive.cs index 0c44758..37947db 100644 --- a/RDMSharpTests/Devices/TestRDMSendReceive.cs +++ b/RDMSharpTests/Devices/TestRDMSendReceive.cs @@ -1,6 +1,4 @@ using RDMSharpTests.Devices.Mock; -using System.Diagnostics; -using System.Reflection.Metadata; namespace RDMSharpTests.RDM.Devices { @@ -29,53 +27,60 @@ public async Task TestDevice1() var parameterValuesRemote = remote.GetAllParameterValues(); var parameterValuesGenerated = generated.GetAllParameterValues(); - Assert.Multiple(() => - { + //Assert.Multiple(() => + //{ + Assert.That(parameterValuesGenerated.Keys, Is.EquivalentTo(parameterValuesRemote.Keys)); foreach (var parameter in parameterValuesGenerated.Keys) { - Assert.That(parameterValuesRemote.Keys, Contains.Item(parameter)); - Assert.That(parameterValuesGenerated[parameter], Is.EqualTo(parameterValuesRemote[parameter])); + Assert.That(parameterValuesRemote.Keys, Contains.Item(parameter), $"Tested Parameter {parameter}"); + if (parameterValuesGenerated[parameter] is Array) + Assert.That(parameterValuesGenerated[parameter], Is.EquivalentTo((Array)parameterValuesRemote[parameter]), $"Tested Parameter {parameter}"); + else + Assert.That(parameterValuesGenerated[parameter], Is.EqualTo(parameterValuesRemote[parameter]), $"Tested Parameter {parameter}"); } foreach (var parameter in parameterValuesRemote.Keys) { - Assert.That(parameterValuesGenerated.Keys, Contains.Item(parameter)); - Assert.That(parameterValuesRemote[parameter], Is.EqualTo(parameterValuesGenerated[parameter])); + Assert.That(parameterValuesGenerated.Keys, Contains.Item(parameter), $"Tested Parameter {parameter}"); + if (parameterValuesRemote[parameter] is Array) + Assert.That(parameterValuesRemote[parameter], Is.EquivalentTo((Array)parameterValuesGenerated[parameter]), $"Tested Parameter {parameter}"); + else + Assert.That(parameterValuesRemote[parameter], Is.EqualTo(parameterValuesGenerated[parameter]), $"Tested Parameter {parameter}"); } Assert.That(parameterValuesRemote, Has.Count.EqualTo(parameterValuesGenerated.Count)); - }); + //}); - Assert.Multiple(() => - { + //Assert.Multiple(() => + //{ Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.DEVICE_INFO], Is.EqualTo(generated.DeviceInfo)); Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.DEVICE_LABEL], Is.EqualTo(generated.DeviceLabel)); Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.DEVICE_MODEL_DESCRIPTION], Is.EqualTo(generated.DeviceModelDescription)); Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.MANUFACTURER_LABEL], Is.EqualTo(generated.ManufacturerLabel)); Assert.That(((RDMDMXPersonality)remote.GetAllParameterValues()[ERDM_Parameter.DMX_PERSONALITY]).Index, Is.EqualTo(generated.CurrentPersonality)); - }); + //}); await remote.SetParameter(ERDM_Parameter.DMX_START_ADDRESS, (ushort)512); - Assert.Multiple(() => - { + //Assert.Multiple(() => + //{ Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.DMX_START_ADDRESS], Is.EqualTo(512)); Assert.That(generated.DMXAddress, Is.EqualTo(512)); - }); + //}); await remote.SetParameter(ERDM_Parameter.DMX_PERSONALITY, (byte)3); - Assert.Multiple(() => - { + //Assert.Multiple(() => + //{ Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.DMX_PERSONALITY], Is.EqualTo(3)); Assert.That(generated.CurrentPersonality, Is.EqualTo(3)); - }); + //}); string label = "Changed Device Label"; await remote.SetParameter(ERDM_Parameter.DEVICE_LABEL, label); - Assert.Multiple(() => - { + //Assert.Multiple(() => + //{ Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.DEVICE_LABEL], Is.EqualTo(label)); Assert.That(generated.DeviceLabel, Is.EqualTo(label)); - }); - Assert.Multiple(async () => - { + //}); + //Assert.Multiple(async () => + //{ Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.IDENTIFY_DEVICE], Is.False); Assert.That(generated.GetAllParameterValues()[ERDM_Parameter.IDENTIFY_DEVICE], Is.False); await remote.SetParameter(ERDM_Parameter.IDENTIFY_DEVICE, true); @@ -84,9 +89,9 @@ public async Task TestDevice1() await remote.SetParameter(ERDM_Parameter.IDENTIFY_DEVICE, false); Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.IDENTIFY_DEVICE], Is.False); Assert.That(generated.GetAllParameterValues()[ERDM_Parameter.IDENTIFY_DEVICE], Is.False); - }); - Assert.Multiple(() => - { + //}); + //Assert.Multiple(() => + //{ Assert.Throws(typeof(NotSupportedException), () => { generated.TrySetParameter(ERDM_Parameter.DEVICE_INFO, new RDMDeviceInfo()); }); Assert.Throws(typeof(NotSupportedException), () => { generated.TrySetParameter(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION, new RDMDMXPersonalityDescription(1, 2, "dasdad")); }); Assert.Throws(typeof(NotSupportedException), () => { generated.TrySetParameter(ERDM_Parameter.LANGUAGE, "de"); }); @@ -94,7 +99,7 @@ public async Task TestDevice1() Assert.Throws(typeof(NotSupportedException), () => { generated.TrySetParameter(ERDM_Parameter.DEVICE_LABEL, "Test"); }); Assert.Throws(typeof(NotSupportedException), () => { generated.TrySetParameter(ERDM_Parameter.DISC_MUTE, null); }); Assert.Throws(typeof(NotSupportedException), () => { generated.TrySetParameter(ERDM_Parameter.DEVICE_LABEL, new RDMDeviceInfo()); }); - }); + //}); } [Test] diff --git a/RDMSharpTests/Metadata/JSON/MetadataJSONObjectDefineTestSubject.cs b/RDMSharpTests/Metadata/JSON/MetadataJSONObjectDefineTestSubject.cs new file mode 100644 index 0000000..7cf019b --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/MetadataJSONObjectDefineTestSubject.cs @@ -0,0 +1,66 @@ +using RDMSharp.Metadata; +using System.Collections.Concurrent; +using System.Reflection; + +namespace RDMSharpTests.Metadata.JSON +{ + public class MetadataJSONObjectDefineTestSubject + { + public static readonly object[] TestSubjects = getTestSubjects(); + internal static string[] GetResources() + { + var assembly = Assembly.GetExecutingAssembly(); + return assembly.GetManifestResourceNames(); + } + private static object[] getTestSubjects() + { + List instances = new List(); + List metadataVersionList = new List(); + metadataVersionList.AddRange(MetadataFactory.GetResources().Select(r => new MetadataVersion(r))); + var schemaList = MetadataFactory.GetMetadataSchemaVersions(); + ConcurrentDictionary versionSchemas = new ConcurrentDictionary(); + + foreach (var mv in metadataVersionList.Where(_mv => !_mv.IsSchema)) + { + var _schema = schemaList.First(s => s.Version.Equals(mv.Version)); + if (!versionSchemas.TryGetValue(_schema.Version, out MetadataBag schema)) + { + schema = new MetadataBag(_schema); + versionSchemas.TryAdd(_schema.Version, schema); + } + instances.Add(new MetadataJSONObjectDefineTestSubject(schema, new MetadataBag(mv))); + } + foreach (var mv in GetResources().Select(r => new MetadataVersion(r))) + { + var _schema = schemaList.First(s => s.Version.Equals(mv.Version)); + if (!versionSchemas.TryGetValue(_schema.Version, out MetadataBag schema)) + { + schema = new MetadataBag(_schema); + versionSchemas.TryAdd(_schema.Version, schema); + } + instances.Add(new MetadataJSONObjectDefineTestSubject(schema, new MetadataBag(mv.Version, mv.Name, mv.IsSchema, getContent(mv.Path), mv.Path))); + } + return instances.ToArray(); + } + private static string getContent(string path) + { + if (string.IsNullOrWhiteSpace(path)) + return null; + var assembly = typeof(MetadataJSONObjectDefineTestSubject).Assembly; + using Stream stream = assembly.GetManifestResourceStream(path); + using StreamReader reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + public readonly MetadataBag Schema; + public readonly MetadataBag Define; + + public override string ToString() => Define.Name; + + public MetadataJSONObjectDefineTestSubject(MetadataBag schema, MetadataBag define) + { + Schema = schema; + Define = define; + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/MetadataJSONObjectDefineTests.cs b/RDMSharpTests/Metadata/JSON/MetadataJSONObjectDefineTests.cs new file mode 100644 index 0000000..26167bf --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/MetadataJSONObjectDefineTests.cs @@ -0,0 +1,250 @@ +using Json.Schema; +using Newtonsoft.Json.Linq; +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using RDMSharp.Metadata.JSON.OneOfTypes; +using RDMSharp.RDM; +using System.Text.Json; +using System.Text.Json.Nodes; + +namespace RDMSharpTests.Metadata.JSON +{ + [TestFixtureSource(typeof(MetadataJSONObjectDefineTestSubject), nameof(MetadataJSONObjectDefineTestSubject.TestSubjects))] + public class MetadataJSONObjectDefineTests + { + private readonly MetadataJSONObjectDefineTestSubject testSubject; + + public MetadataJSONObjectDefineTests(MetadataJSONObjectDefineTestSubject _TestSubject) + { + testSubject = _TestSubject; + } + + + [Test] + public void TestValidateAgainstSchema() + { + JsonSchema jsonSchema = JsonSchema.FromText(testSubject.Schema.Content); + var result = jsonSchema.Evaluate(JsonNode.Parse(testSubject.Define.Content)); + Assert.That(result, Is.Not.Null); + if (!testSubject.Define.Name.ToLower().Contains("invalid")) + Assert.That(result.IsValid, Is.True); + else if (testSubject.Define.Name.ToLower().Contains("invalid_but_schema_is_valid")) + Assert.That(result.IsValid, Is.True); + else + Assert.That(result.IsValid, Is.False); + } + [Test] + public void TestDeseriaizeAndSerialize() + { + try + { + MetadataJSONObjectDefine deserialized = JsonSerializer.Deserialize(testSubject.Define.Content); + Assert.That(deserialized.Version, Is.AtLeast(1)); + Assert.That(deserialized.Name, Is.Not.WhiteSpace); + Assert.That(deserialized.Name, Is.Not.Empty); + string serialized = JsonSerializer.Serialize(deserialized); + + var original = JToken.Parse(PrittyJSON(testSubject.Define.Content)); + var smashed = JToken.Parse(PrittyJSON(serialized)); + + Assert.Multiple(() => + { + Assert.That(JToken.DeepEquals(smashed, original)); + + + Warn.Unless(PrittyJSON(serialized), Is.EqualTo(PrittyJSON(testSubject.Define.Content))); + }); + } + catch (JsonException ex) + { + if (testSubject.Define.Name.ToLower().Contains("invalid")) + return; + +#if !NET7_0_OR_GREATER + Warn.If(ex.Message, Is.EqualTo("Unexpected JSON format Type: int128 for FieldContainer.").Or.EqualTo("Unexpected JSON format Type: uint128 for FieldContainer."), "Due to .NET6 limitations"); + return; +#else + throw; +#endif + } + } + [Test] + public void TestDeseriaizedObject() + { + MetadataJSONObjectDefine deserialized = null; + testString(testSubject.Define.ToString()); + try + { + deserialized = JsonSerializer.Deserialize(testSubject.Define.Content); + } + catch (JsonException ex) + { + if (testSubject.Define.Name.ToLower().Contains("invalid")) + return; +#if !NET7_0_OR_GREATER + Warn.If(ex.Message, Is.EqualTo("Unexpected JSON format Type: int128 for FieldContainer.").Or.EqualTo("Unexpected JSON format Type: uint128 for FieldContainer."), "Due to .NET6 limitations"); + return; +#else + throw; +#endif + } + Assert.That(deserialized.Version, Is.AtLeast(1)); + Assert.That(deserialized.Name, Is.Not.WhiteSpace); + Assert.That(deserialized.Name, Is.Not.Empty); + + testString(deserialized.ToString()); + + if (deserialized.GetRequestSubdeviceRange != null) + { + testString(string.Join("; ", deserialized.GetRequestSubdeviceRange.Select(r => r.ToString()))!); + } + if (deserialized.GetResponseSubdeviceRange != null) + { + testString(string.Join("; ", deserialized.GetResponseSubdeviceRange.Select(r => r.ToString()))!); + } + if (deserialized.SetRequestsSubdeviceRange != null) + { + testString(string.Join("; ", deserialized.SetRequestsSubdeviceRange.Select(r => r.ToString()))!); + } + if (deserialized.SetResponseSubdeviceRange != null) + { + testString(string.Join("; ", deserialized.SetResponseSubdeviceRange.Select(r => r.ToString()))!); + } + + if (deserialized.GetRequest != null) + { + testCommand(deserialized.GetRequest.Value); + deserialized.GetCommand(Command.ECommandDublicte.GetRequest, out Command? command); + if (command != null) + testCommand(command.Value); + } + + if (deserialized.GetResponse != null) + { + testCommand(deserialized.GetResponse.Value); + deserialized.GetCommand(Command.ECommandDublicte.GetResponse, out Command? command); + if (command != null) + testCommand(command.Value); + } + + if (deserialized.SetRequest != null) + { + testCommand(deserialized.SetRequest.Value); + deserialized.GetCommand(Command.ECommandDublicte.SetRequest, out Command? command); + if (command != null) + testCommand(command.Value); + } + + if (deserialized.SetResponse != null) + { + testCommand(deserialized.SetResponse.Value); + deserialized.GetCommand(Command.ECommandDublicte.SetResponse, out Command? command); + if (command != null) + testCommand(command.Value); + } + + + static void testString(string str) + { + Assert.That(str, Is.Not.WhiteSpace); + Assert.That(str, Is.Not.Empty); + Assert.That(str, Does.Not.Contain("{")); + Assert.That(str, Does.Not.Contain("}")); + } + static void testCommand(Command command) + { + testString(command.ToString()!); + PDL? pdl = null; + if (command.EnumValue is Command.ECommandDublicte _enum) + { + Assert.That(command.GetIsEmpty(), Is.False); + testString(_enum.ToString()!); + return; + } + + Assert.DoesNotThrow(() => { pdl = command.GetDataLength(); }); + Assert.That(pdl.HasValue, Is.True); + + if (command.SingleField is OneOfTypes singleField) + { + Assert.That(command.GetIsEmpty(), Is.False); + testString(singleField.ToString()!); + if (singleField.ObjectType is CommonPropertiesForNamed common) + testCommon(common); + else if (singleField.ReferenceType is ReferenceType reference) + testReference(reference); + return; + } + else if (command.ListOfFields is OneOfTypes[] listOfFields) + { + if (listOfFields.Length != 0) + { + Assert.That(command.GetIsEmpty(), Is.False); + testString(string.Join("; ", listOfFields.Select(r => r.ToString()))!); + foreach (var field in listOfFields) + { + if (field.ObjectType is CommonPropertiesForNamed common) + testCommon(common); + else if (field.ReferenceType is ReferenceType reference) + testReference(reference); + } + return; + } + } + Assert.That(command.GetIsEmpty(), Is.True); + } + static void testCommon(CommonPropertiesForNamed common) + { + testString(common.ToString()!); + if (common is IntegerType integerByte) + testIntegerType(integerByte); + else if (common is IntegerType integerSByte) + testIntegerType(integerSByte); + else if (common is IntegerType integerShort) + testIntegerType(integerShort); + else if (common is IntegerType integerUShort) + testIntegerType(integerUShort); + else if (common is IntegerType integerInt) + testIntegerType(integerInt); + else if (common is IntegerType integerUInt) + testIntegerType(integerUInt); + else if (common is IntegerType integerLong) + testIntegerType(integerLong); + else if (common is IntegerType integerULong) + testIntegerType(integerULong); +#if NET7_0_OR_GREATER + else if (common is IntegerType integerInt128) + testIntegerType(integerInt128); + else if (common is IntegerType integerUInt128) + testIntegerType(integerUInt128); +#endif + } + static void testReference(ReferenceType reference) + { + testString(reference.ToString()); + Assert.That(reference.Command, Is.EqualTo(Command.ECommandDublicte.GetRequest).Or.EqualTo(Command.ECommandDublicte.GetResponse).Or.EqualTo(Command.ECommandDublicte.SetRequest).Or.EqualTo(Command.ECommandDublicte.SetResponse)); + Assert.That(reference.Pointer, Is.AtLeast(0)); + } + static void testIntegerType(IntegerType integerType) + { + testString(integerType.ToString()!); + if (integerType.Ranges != null) + foreach (Range range in integerType.Ranges) + testString(range.ToString()!); + } + } + + private static string PrittyJSON(string jsonString) + { + var jsonObject = JsonSerializer.Deserialize(jsonString); + + var options = new JsonSerializerOptions + { + WriteIndented = false, + }; + + string formattedJson = JsonSerializer.Serialize(jsonObject, options); + return formattedJson; + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestBitFieldType.cs b/RDMSharpTests/Metadata/JSON/TestBitFieldType.cs new file mode 100644 index 0000000..f95bf1b --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestBitFieldType.cs @@ -0,0 +1,90 @@ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON.OneOfTypes; +using RDMSharp.RDM; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestBitFieldType + { + [Test] + public void TestMany() + { + var bitTypes=new BitType[2]; + bitTypes[0] = new BitType("NAME11", "DISPLAY_NAME11", "NOTES11", null, null, 2, false, false); + bitTypes[1] = new BitType("NAME22", "DISPLAY_NAME22", "NOTES22", null, null, 4, false, false); + var bitFieldType = new BitFieldType("NAME", "DISPLAY_NAME", "NOTES", null, "bitField",16, false, bitTypes); + Assert.That(bitFieldType.Size, Is.EqualTo(16)); + Assert.That(bitFieldType.Bits, Has.Length.EqualTo(2)); + + Assert.DoesNotThrow(() => + { + PDL pdl = bitFieldType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(2)); + }); + + Assert.Throws(typeof(ArgumentException), () => bitFieldType = new BitFieldType("NAME", "DISPLAY_NAME", "NOTES", null, "botField", 16, false, bitTypes)); + Assert.Throws(typeof(ArgumentOutOfRangeException), () => bitFieldType = new BitFieldType("NAME", "DISPLAY_NAME", "NOTES", null, "bitField", 7, false, bitTypes)); + + + bitTypes = new BitType[3]; + bitTypes[0] = new BitType("NAME11", 2); + bitTypes[1] = new BitType("NAME22", 4); + bitTypes[2] = new BitType("NAME33", 15); + bitFieldType = new BitFieldType("NAME_BIT_FIELD", 16, bitTypes); + var dataTree= new DataTree(bitFieldType.Name,0,new DataTree[] { new DataTree(bitTypes[0].Name, 0, true), new DataTree(bitTypes[1].Name, 1, true), new DataTree(bitTypes[2].Name, 2, true), }); + + DoParseDataTest(bitFieldType, dataTree, new byte[] { 0b00010100, 0b10000000 }); + + bitFieldType = new BitFieldType("NAME_BIT_FIELD", 16, bitTypes, true); + dataTree = new DataTree(bitFieldType.Name, 0, new DataTree[] { new DataTree(bitTypes[0].Name, 0, false), new DataTree(bitTypes[1].Name, 1, false), new DataTree(bitTypes[2].Name, 2, false), }); + Assert.That(bitFieldType.ValueForUnspecified, Is.True); + DoParseDataTest(bitFieldType, dataTree, new byte[] { 0b11101011, 0b01111111 }); + } + private void DoParseDataTest(BitFieldType bitFieldType, DataTree dataTree, byte[] expectedData, string message = null) + { + Assert.Multiple(() => + { + Assert.That(dataTree.Value, Is.Null); + Assert.That(dataTree.Children, Is.Not.Null); + var data = new byte[0]; + Assert.DoesNotThrow(() => data = bitFieldType.ParsePayloadToData(dataTree), message); + Assert.That(data, Is.EqualTo(expectedData), message); + + byte[] clonaData = new byte[data.Length]; + Array.Copy(data, clonaData, clonaData.Length); + var parsedDataTree = bitFieldType.ParseDataToPayload(ref clonaData); + Assert.That(clonaData, Has.Length.EqualTo(0), message); + + Assert.That(parsedDataTree, Is.EqualTo(dataTree), message); + Assert.That(parsedDataTree.Value, Is.Null); + + //Test for short Data & PDL Issue + clonaData = new byte[data.Length - 1]; + Array.Copy(data, clonaData, clonaData.Length); + Assert.DoesNotThrow(() => parsedDataTree = bitFieldType.ParseDataToPayload(ref clonaData)); + Assert.That(parsedDataTree.Issues, Is.Not.Null); + Assert.That(parsedDataTree.Value, Is.Null); + Assert.That(parsedDataTree.Children, Is.Not.Null); + + Assert.Throws(typeof(ArithmeticException), () => data = bitFieldType.ParsePayloadToData(new DataTree("Different Name", dataTree.Index, children: dataTree.Children)), message); + Assert.Throws(typeof(ArithmeticException), () => data = bitFieldType.ParsePayloadToData(new DataTree(dataTree.Name, dataTree.Index, children: dataTree.Children?.Take(2).ToArray())), message); + + var children = dataTree.Children!.ToArray(); + children[1] = new DataTree("Other Name", children[1].Index, children[1].Value); + Assert.Throws(typeof(ArithmeticException), () => data = bitFieldType.ParsePayloadToData(new DataTree(dataTree.Name, dataTree.Index, children: children)), message); + + children = dataTree.Children!.ToArray(); + children[1] = new DataTree(children[1].Name, 3, children[1].Value); + Assert.Throws(typeof(ArithmeticException), () => data = bitFieldType.ParsePayloadToData(new DataTree(dataTree.Name, dataTree.Index, children: children)), message); + + children = dataTree.Children!.ToArray(); + children[1] = new DataTree(children[1].Name, 0, children[1].Value); + Assert.Throws(typeof(ArithmeticException), () => data = bitFieldType.ParsePayloadToData(new DataTree(dataTree.Name, dataTree.Index, children: children)), message); + + children = dataTree.Children!.ToArray(); + children[1] = new DataTree(children[1].Name, children[1].Index, 3); + Assert.Throws(typeof(ArithmeticException), () => data = bitFieldType.ParsePayloadToData(new DataTree(dataTree.Name, dataTree.Index, children: children)), message); + }); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestBitType.cs b/RDMSharpTests/Metadata/JSON/TestBitType.cs new file mode 100644 index 0000000..e0d2bd8 --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestBitType.cs @@ -0,0 +1,19 @@ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON.OneOfTypes; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestBitType + { + [Test] + public void TestMany() + { + var bitType = new BitType("NAME", "DISPLAY_NAME", "NOTES", null, "bit", 1, true, false); + Assert.That(bitType.Index, Is.EqualTo(1)); + Assert.Throws(typeof(NotSupportedException), () => bitType.GetDataLength()); + byte[] bytes = new byte[0]; + Assert.Throws(typeof(NotSupportedException), () => bitType.ParseDataToPayload(ref bytes)); + Assert.Throws(typeof(NotSupportedException), () => bitType.ParsePayloadToData(new DataTree())); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestBooleanType.cs b/RDMSharpTests/Metadata/JSON/TestBooleanType.cs new file mode 100644 index 0000000..79fa755 --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestBooleanType.cs @@ -0,0 +1,73 @@ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON.OneOfTypes; +using RDMSharp.RDM; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestBooleanType + { + [Test] + public void TestMany() + { + var labeledBooleanType = new LabeledBooleanType[2]; + labeledBooleanType[0] = new LabeledBooleanType("NAME11", null, "NOTES11", null, false); + labeledBooleanType[1] = new LabeledBooleanType("NAME22", "DISPLAY_NAME22", "NOTES22", null, true); + var booleanType = new BooleanType("NAME", "DISPLAY_NAME", "NOTES", null, "boolean", labeledBooleanType); + Assert.That(booleanType.Labels, Has.Length.EqualTo(2)); + + Assert.DoesNotThrow(() => + { + PDL pdl = booleanType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(1)); + }); + + DoParseDataTest(booleanType, false, new byte[] { 0x00 }); + DoParseDataTest(booleanType, true, new byte[] { 0x01 }); + + booleanType = new BooleanType("NAME", "DISPLAY_NAME", "NOTES", null, "boolean", null); + DoParseDataTest(booleanType, false, new byte[] { 0x00 }); + DoParseDataTest(booleanType, true, new byte[] { 0x01 }); + + Assert.Throws(typeof(ArgumentException), () => booleanType = new BooleanType("NAME", "DISPLAY_NAME", "NOTES", null, "bolean", labeledBooleanType)); + + labeledBooleanType = new LabeledBooleanType[1]; + labeledBooleanType[0] = new LabeledBooleanType("NAME11", "DISPLAY_NAME11", "NOTES11", null, false); + Assert.Throws(typeof(ArgumentException), () => booleanType = new BooleanType("NAME", "DISPLAY_NAME", "NOTES", null, "boolean", labeledBooleanType)); + + labeledBooleanType = new LabeledBooleanType[3]; + labeledBooleanType[0] = new LabeledBooleanType("NAME11", false); + labeledBooleanType[1] = new LabeledBooleanType("NAME22", "DISPLAY_NAME22", "NOTES22", null, true); + labeledBooleanType[2] = new LabeledBooleanType("NAME33", "DISPLAY_NAME33", "NOTES33", null, false); + Assert.Throws(typeof(ArgumentException), () => booleanType = new BooleanType("NAME", "DISPLAY_NAME", "NOTES", null, "boolean", labeledBooleanType)); + + labeledBooleanType = new LabeledBooleanType[2]; + labeledBooleanType[0] = new LabeledBooleanType("NAME11", "DISPLAY_NAME11", "NOTES11", null, false); + labeledBooleanType[1] = new LabeledBooleanType("NAME22", "DISPLAY_NAME22", "NOTES22", null, false); + Assert.Throws(typeof(ArgumentException), () => booleanType = new BooleanType("NAME", "DISPLAY_NAME", "NOTES", null, "boolean", labeledBooleanType)); + } + private void DoParseDataTest(BooleanType booleanType, bool value, byte[] expectedData, string message = null) + { + var dataTree = new DataTree(booleanType.Name, 0, value); + var data = new byte[0]; + Assert.DoesNotThrow(() => data = booleanType.ParsePayloadToData(dataTree), message); + Assert.That(data, Is.EqualTo(expectedData), message); + + byte[] clonaData = new byte[data.Length]; + Array.Copy(data, clonaData, clonaData.Length); + var parsedDataTree = booleanType.ParseDataToPayload(ref clonaData); + Assert.That(clonaData, Has.Length.EqualTo(0), message); + + Assert.That(parsedDataTree, Is.EqualTo(dataTree), message); + + //Test for short Data & PDL Issue + clonaData = new byte[data.Length - 1]; + Array.Copy(data, clonaData, clonaData.Length); + Assert.DoesNotThrow(() => parsedDataTree = booleanType.ParseDataToPayload(ref clonaData)); + Assert.That(parsedDataTree.Issues, Is.Not.Null); + Assert.That(parsedDataTree.Value, Is.Not.Null); + + Assert.Throws(typeof(ArithmeticException), () => data = booleanType.ParsePayloadToData(new DataTree("Different Name", dataTree.Index, dataTree.Value)), message); + Assert.Throws(typeof(ArithmeticException), () => data = booleanType.ParsePayloadToData(new DataTree(dataTree.Name, dataTree.Index, 234)), message); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestBytesType.cs b/RDMSharpTests/Metadata/JSON/TestBytesType.cs new file mode 100644 index 0000000..2aad6f7 --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestBytesType.cs @@ -0,0 +1,339 @@ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON.OneOfTypes; +using RDMSharp.RDM; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestBytesType + { + [Test] + public void TestMany() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", null, null, null); + Assert.That(bytesType.MinLength, Is.Null); + Assert.That(bytesType.MaxLength, Is.Null); + + bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", null, 1, null); + Assert.That(bytesType.MinLength, Is.EqualTo(1)); + Assert.That(bytesType.MaxLength, Is.Null); + + Assert.DoesNotThrow(() => + { + PDL pdl = bytesType.GetDataLength(); + Assert.That(pdl.Value, Is.Null); + Assert.That(pdl.MinLength, Is.EqualTo(1)); + Assert.That(pdl.MaxLength, Is.EqualTo(PDL.MAX_LENGTH)); + }); + + bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", null, 1, 3); + Assert.That(bytesType.MinLength, Is.EqualTo(1)); + Assert.That(bytesType.MaxLength, Is.EqualTo(3)); + + Assert.DoesNotThrow(() => + { + PDL pdl = bytesType.GetDataLength(); + Assert.That(pdl.Value, Is.Null); + Assert.That(pdl.MinLength, Is.EqualTo(1)); + Assert.That(pdl.MaxLength, Is.EqualTo(3)); + }); + + Assert.Throws(typeof(ArgumentException), () => bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bites", null, 1, 5)); + Assert.Throws(typeof(ArgumentOutOfRangeException), () => bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", null, 6, 5)); + Assert.Throws(typeof(ArgumentOutOfRangeException), () => bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", null, 4294567890, null)); + Assert.Throws(typeof(ArgumentOutOfRangeException), () => bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", null, 2, 4294567890)); + } + [Test] + public void TestParseUID() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "uid", null, null); + Assert.That(bytesType.GetDataLength().Value, Is.EqualTo(6)); + var uid = new UID(0x4646, 0x12345678); + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, uid)); + Assert.That(data, Is.EqualTo(new byte[] { 0x46, 0x46, 0x12, 0x34, 0x56, 0x78 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(uid)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "uid", null, null).ParsePayloadToData(dataTree)); + Assert.Throws(typeof(ArithmeticException), () => new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "xyz", null, null).ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseUIDArrayEmpty() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "uid[]", null, null); + Assert.That(bytesType.GetDataLength().MinLength, Is.EqualTo(0)); + var uidArray = new UID[0]; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, uidArray)); + Assert.That(data, Is.EqualTo(new byte[0])); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Null); + } + [Test] + public void TestParseUIDArray() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "uid[]", null, null); + Assert.That(bytesType.GetDataLength().MinLength, Is.EqualTo(0)); + var uidArray = new UID[] { new UID(0x4646, 0x12345678) , new UID(0x4646, 0x12345678) }; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, uidArray)); + Assert.That(data, Is.EqualTo(new byte[] { 0x46, 0x46, 0x12, 0x34, 0x56, 0x78, 0x46, 0x46, 0x12, 0x34, 0x56, 0x78 })); + var corrupData = new List(); + corrupData.AddRange(data); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.EqualTo(uidArray)); + + corrupData.Add(1); + corrupData.Add(2); + data= corrupData.ToArray(); + dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(2)); + Assert.That(data, Is.EqualTo(new byte[] { 1, 2 })); + Assert.That(dataTree.Value, Is.EqualTo(uidArray)); + Assert.That(dataTree.Issues, Has.Length.EqualTo(2)); + } + + [Test] + public void TestParseIPv4() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "ipv4", null, null); + Assert.That(bytesType.GetDataLength().Value, Is.EqualTo(4)); + var ipv4 = new IPv4Address(192,168,178,254); + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, ipv4)); + Assert.That(data, Is.EqualTo(new byte[] { 192, 168, 178, 254 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(ipv4)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "ipv4", null, null).ParsePayloadToData(dataTree)); + Assert.Throws(typeof(ArithmeticException), () => new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "xyz", null, null).ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseIPv6() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "ipv6", null, null); + Assert.That(bytesType.GetDataLength().Value, Is.EqualTo(16)); + var ipv6 = IPv6Address.LocalHost; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, ipv6)); + Assert.That(data, Is.EqualTo(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(ipv6)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "ipv6", null, null).ParsePayloadToData(dataTree)); + Assert.Throws(typeof(ArithmeticException), () => new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "xyz", null, null).ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseMAC() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "mac-address", null, null); + Assert.That(bytesType.GetDataLength().Value, Is.EqualTo(6)); + var mac = new MACAddress(new byte[] { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC }); + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, mac)); + Assert.That(data, Is.EqualTo(new byte[] { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(mac)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "mac-address", null, null).ParsePayloadToData(dataTree)); + Assert.Throws(typeof(ArithmeticException), () => new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "xyz", null, null).ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseGUID() + { + string[] formates = new string[] { "uuid", "guid" }; + foreach (var formate in formates) + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", formate, null, null); + Assert.That(bytesType.GetDataLength().Value, Is.EqualTo(16)); + var guid = new Guid(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }); + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, guid)); + Assert.That(data, Is.EqualTo(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(guid)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", formate, null, null).ParsePayloadToData(dataTree)); + Assert.Throws(typeof(ArithmeticException), () => new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "xyz", null, null).ParsePayloadToData(dataTree)); + } + } + [Test] + public void TestParseDouble() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "double", null, null); + Assert.That(bytesType.GetDataLength().Value, Is.EqualTo(8)); + var _double = 0.252536d; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, _double)); + Assert.That(data, Is.EqualTo(new byte[] { 142, 2, 68, 193, 140, 41, 208, 63 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(_double)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "double", null, null).ParsePayloadToData(dataTree)); + Assert.Throws(typeof(ArithmeticException), () => new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "xyz", null, null).ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseFloat() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "float", null, null); + Assert.That(bytesType.GetDataLength().Value, Is.EqualTo(4)); + var _float = 0.252536f; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, _float)); + Assert.That(data, Is.EqualTo(new byte[] { 102, 76, 129, 62 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(_float)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "float", null, null).ParsePayloadToData(dataTree)); + Assert.Throws(typeof(ArithmeticException), () => new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "xyz", null, null).ParsePayloadToData(dataTree)); + } + [Test] + public void TestParsePID() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "pid", null, null); + Assert.That(bytesType.GetDataLength().Value, Is.EqualTo(2)); + var pid = ERDM_Parameter.CURVE; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, pid)); + Assert.That(data, Is.EqualTo(new byte[] { 0x03, 0x043 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(pid)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "pid", null, null).ParsePayloadToData(dataTree)); + Assert.Throws(typeof(ArithmeticException), () => new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "xyz", null, null).ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseASCII() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "ascii", null, null); + var ascii = "This is ASCII"; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, ascii)); + Assert.That(data, Is.EqualTo(new byte[] { 84, 104, 105, 115, 32, 105, 115, 32, 65, 83, 67, 73, 73 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(ascii)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "ascii", null, null).ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseUTF8() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "utf8", null, null); + var utf8 = "äöü߀!"; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, utf8)); + Assert.That(data, Is.EqualTo(new byte[] { 195, 164, 195, 182, 195, 188, 195, 159, 226, 130, 172, 33 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(utf8)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "utf8", null, null).ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseUTF32() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "utf32", null, null); + var utf32 = "😊🚀🌍💡📚✈️"; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, utf32)); + Assert.That(data, Is.EqualTo(new byte[] { 10, 246, 1, 0, 128, 246, 1, 0, 13, 243, 1, 0, 161, 244, 1, 0, 218, 244, 1, 0, 8, 39, 0, 0, 15, 254, 0, 0 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(utf32)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "utf32", null, null).ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseUnicode() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "unicode", null, null); + var unicode = "ÄÖÜß😊"; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, unicode)); + Assert.That(data, Is.EqualTo(new byte[] { 196, 0, 214, 0, 220, 0, 223, 0, 61, 216, 10, 222 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(unicode)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "unicode", null, null).ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseBigEndianUnicode() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "big_edian_unicode", null, null); + var big_edian_unicode = "ÄÖÜß😊"; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, big_edian_unicode)); + Assert.That(data, Is.EqualTo(new byte[] { 0, 196, 0, 214, 0, 220, 0, 223, 216, 61, 222, 10 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(big_edian_unicode)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "big_edian_unicode", null, null).ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseLatin1() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "latin1", null, null); + var latin1 = "Café"; ; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, latin1)); + Assert.That(data, Is.EqualTo(new byte[] { 67, 97, 102, 233 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(latin1)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "latin1", null, null).ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseFallbackString() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", null, null, null); + var utf8 = "äöü߀!"; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, utf8)); + Assert.That(data, Is.EqualTo(new byte[] { 195, 164, 195, 182, 195, 188, 195, 159, 226, 130, 172, 33 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + } + [Test] + public void TestParseFallbackUTF8Array() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "utf8[]", null, null); + var utf8 = "äöü߀!"; + var array = new string[] { utf8, utf8 }; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, array)); + Assert.That(data, Is.EqualTo(new byte[] { 195, 164, 195, 182, 195, 188, 195, 159, 226, 130, 172, 33, 0, 195, 164, 195, 182, 195, 188, 195, 159, 226, 130, 172, 33, 0 })); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + } + [Test] + public void TestParseFallbackByteArray() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", null, null, null); + var bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + var data = bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, bytes)); + Assert.That(data, Is.EqualTo(bytes)); + var dataTree = bytesType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(bytes)); + } + [Test] + public void TestParseFallbackUnknownType() + { + var bytesType = new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "UNKNOWN", null, null); + Assert.Throws(typeof(ArithmeticException), () => bytesType.ParsePayloadToData(new DataTree(bytesType.Name, 0, DateTime.Now))); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestCommand.cs b/RDMSharpTests/Metadata/JSON/TestCommand.cs new file mode 100644 index 0000000..09bfda6 --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestCommand.cs @@ -0,0 +1,15 @@ +using RDMSharp.Metadata.JSON; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestCommand + { + [Test] + public void TestMany() + { + var command = new Command( Command.ECommandDublicte.GetResponse); + Assert.That(command.GetIsEmpty(), Is.False); + Assert.Throws(typeof(NotSupportedException), () => command.GetDataLength()); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestCompoundType.cs b/RDMSharpTests/Metadata/JSON/TestCompoundType.cs new file mode 100644 index 0000000..4b869d0 --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestCompoundType.cs @@ -0,0 +1,100 @@ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON.OneOfTypes; +using RDMSharp.RDM; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestCompoundType + { + [Test] + public void TestMany() + { + OneOfTypes[] oneOf = new OneOfTypes[2]; + oneOf[0] = new OneOfTypes(new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)); + oneOf[1] = new OneOfTypes(new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int8, null, null, null, null, null, null)); + + var compoundType = new CompoundType("NAME", "DISPLAY_NAME", "NOTES", null, "compound", oneOf); + Assert.That(compoundType.Subtypes, Has.Length.EqualTo(2)); + + Assert.DoesNotThrow(() => + { + PDL pdl = compoundType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(2)); + }); + + Assert.Throws(typeof(ArgumentException), () => compoundType = new CompoundType("NAME", "DISPLAY_NAME", "NOTES", null, "kompound", oneOf)); + Assert.Throws(typeof(ArgumentException), () => compoundType = new CompoundType("NAME", "DISPLAY_NAME", "NOTES", null, "compound", null)); + Assert.Throws(typeof(ArgumentException), () => compoundType = new CompoundType("NAME", "DISPLAY_NAME", "NOTES", null, "compound", new OneOfTypes[0])); + + Assert.Throws(typeof(ArithmeticException), () => compoundType.validateDataLength(1)); + Assert.Throws(typeof(ArithmeticException), () => compoundType.validateDataLength(3)); + Assert.DoesNotThrow(() => compoundType.validateDataLength(2)); + } + + [Test] + public void TestParseData1() + { + OneOfTypes[] oneOf = new OneOfTypes[2]; + oneOf[0] = new OneOfTypes(new IntegerType("NAME1", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)); + oneOf[1] = new OneOfTypes(new IntegerType("NAME2", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int8, null, null, null, null, null, null)); + + var compoundType = new CompoundType("NAME", "DISPLAY_NAME", "NOTES", null, "compound", oneOf); + + DataTree dataTree = new DataTree(compoundType.Name, 0, new DataTree[] { new DataTree(oneOf[0].ObjectType.Name, 0, (byte)33), new DataTree(oneOf[1].ObjectType.Name, 1, (sbyte)-22) }); + byte[] data = compoundType.ParsePayloadToData(dataTree); + Assert.That(data, Is.EqualTo(new byte[] { 33, 234 })); + + DataTree dataTreeResult = compoundType.ParseDataToPayload(ref data); + Assert.That(dataTreeResult, Is.EqualTo(dataTree)); + } + + [Test] + public void TestParseDataInvalidName() + { + OneOfTypes[] oneOf = new OneOfTypes[2]; + oneOf[0] = new OneOfTypes(new IntegerType("NAME1", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)); + oneOf[1] = new OneOfTypes(new IntegerType("NAME2", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int8, null, null, null, null, null, null)); + + var compoundType = new CompoundType("NAME", "DISPLAY_NAME", "NOTES", null, "compound", oneOf); + + DataTree dataTree = new DataTree(compoundType.Name+"INVALID", 0, new DataTree[] { new DataTree(oneOf[0].ObjectType.Name, 0, (byte)33), new DataTree(oneOf[1].ObjectType.Name, 1, (sbyte)-22) }); + Assert.Throws(typeof(ArithmeticException), () => compoundType.ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseDataInvalidNameOnChildren() + { + OneOfTypes[] oneOf = new OneOfTypes[2]; + oneOf[0] = new OneOfTypes(new IntegerType("NAME1", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)); + oneOf[1] = new OneOfTypes(new IntegerType("NAME2", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int8, null, null, null, null, null, null)); + + var compoundType = new CompoundType("NAME", "DISPLAY_NAME", "NOTES", null, "compound", oneOf); + + DataTree dataTree = new DataTree(compoundType.Name, 0, new DataTree[] { new DataTree(oneOf[0].ObjectType.Name+ "INVALID", 0, (byte)33), new DataTree(oneOf[1].ObjectType.Name, 1, (sbyte)-22) }); + Assert.Throws(typeof(ArithmeticException), () => compoundType.ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseDataMissingChildrenDataTree() + { + OneOfTypes[] oneOf = new OneOfTypes[2]; + oneOf[0] = new OneOfTypes(new IntegerType("NAME1", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)); + oneOf[1] = new OneOfTypes(new IntegerType("NAME2", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int8, null, null, null, null, null, null)); + + var compoundType = new CompoundType("NAME", "DISPLAY_NAME", "NOTES", null, "compound", oneOf); + + DataTree dataTree = new DataTree(compoundType.Name, 0, new DataTree[] { new DataTree(oneOf[0].ObjectType.Name, 0, (byte)33) }); + Assert.Throws(typeof(ArithmeticException), () => compoundType.ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseSubItemIsEmpty() + { + OneOfTypes[] oneOf = new OneOfTypes[2]; + oneOf[0] = new OneOfTypes(new IntegerType("NAME1", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)); + oneOf[1] = new OneOfTypes(); + + var compoundType = new CompoundType("NAME", "DISPLAY_NAME", "NOTES", null, "compound", oneOf); + + DataTree dataTree = new DataTree(compoundType.Name, 0, new DataTree[] { new DataTree(oneOf[0].ObjectType.Name, 0, (byte)33), new DataTree(null, 1, (sbyte)-22) }); + Assert.Throws(typeof(ArithmeticException), () => compoundType.ParsePayloadToData(dataTree)); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestDataTree.cs b/RDMSharpTests/Metadata/JSON/TestDataTree.cs new file mode 100644 index 0000000..66e7d4b --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestDataTree.cs @@ -0,0 +1,85 @@ +using RDMSharp.Metadata; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestDataTree + { + [Test] + public void TestMany() + { + Assert.Multiple(() => + { + var dataTree = new DataTree(); + Assert.That(dataTree.ToString(), Is.Not.Null); + Assert.Throws(typeof(ArgumentException), () => new DataTree("name", 1, value: new DataTree[0].ToList())); + + Assert.That(new DataTree() == new DataTree(), Is.True); + Assert.That(new DataTree() != new DataTree(), Is.False); + Assert.That(new DataTree().Equals(new DataTree()), Is.True); + Assert.That(((object)new DataTree()).Equals(new DataTree()), Is.True); + Assert.That(((object)new DataTree()).Equals((object)new DataTree()), Is.True); + Assert.That(((object)new DataTree()).Equals(1), Is.False); + + Assert.That(new DataTree("Test", 3, true) == new DataTree("Test", 3, true), Is.True); + Assert.That(new DataTree("Test", 3, true) != new DataTree("Test", 3, true), Is.False); + Assert.That(new DataTree("Test", 3, true).Equals(new DataTree("Test", 3, true)), Is.True); + + Assert.That(new DataTree("Test", 3, true) == new DataTree("Test", 31, true), Is.False); + Assert.That(new DataTree("Test", 3, true) != new DataTree("Test", 31, true), Is.True); + Assert.That(new DataTree("Test", 3, true).Equals(new DataTree("Test", 31, true)), Is.False); + Assert.That(new DataTree("Test", 3, true) == new DataTree("Test", 3, false), Is.False); + Assert.That(new DataTree("Test", 3, true) != new DataTree("Test", 3, false), Is.True); + Assert.That(new DataTree("Test", 3, true).Equals(new DataTree("Test", 3, false)), Is.False); + Assert.That(new DataTree("Test", 3, true) == new DataTree("Test2", 3, true), Is.False); + Assert.That(new DataTree("Test", 3, true) != new DataTree("Test3", 3, true), Is.True); + Assert.That(new DataTree("Test", 3, true).Equals(new DataTree("Test4", 3, true)), Is.False); + Assert.That(new DataTree("Test", 3, true) == new DataTree("Test", 3, null), Is.False); + Assert.That(new DataTree("Test", 3, true) != new DataTree("Test", 3, null), Is.True); + Assert.That(new DataTree("Test", 3, true).Equals(new DataTree("Test", 3, null)), Is.False); + }); + + HashSet dict1 = new HashSet(); + HashSet dict2 = new HashSet(); + HashSet dict3 = new HashSet(); + + dict1.Add(new DataTree()); + dict2.Add(new DataTree()); + dict3.Add(new DataTree()); + + dict1.Add(new DataTree("Test", 1, false)); + dict2.Add(new DataTree("Test", 1, false)); + dict3.Add(new DataTree("Test", 1, true)); + + dict1.Add(new DataTree("Test2", 2, 33)); + dict2.Add(new DataTree("Test2", 2, 33)); + dict3.Add(new DataTree("Test2", 2, 33)); + + Assert.Multiple(() => + { + Assert.That(new DataTree("Test", 3, children: dict1.ToArray()) == new DataTree("Test", 3, children: dict2.ToArray()), Is.True); + Assert.That(new DataTree("Test", 3, children: dict1.ToArray()) != new DataTree("Test", 3, children: dict2.ToArray()), Is.False); + Assert.That(new DataTree("Test", 3, children: dict1.ToArray()).Equals(new DataTree("Test", 3, children: dict2.ToArray())), Is.True); + + Assert.That(new DataTree("Test", 3, children: null) == new DataTree("Test", 3, children: dict3.ToArray()), Is.False); + Assert.That(new DataTree("Test", 3, children: dict1.ToArray()) == new DataTree("Test", 3, children: dict3.ToArray()), Is.False); + Assert.That(new DataTree("Test", 3, children: dict1.ToArray()) != new DataTree("Test", 3, children: dict3.ToArray()), Is.True); + Assert.That(new DataTree("Test", 3, children: dict1.ToArray()).Equals(new DataTree("Test", 3, children: dict3.ToArray())), Is.False); + }); + + DataTreeIssue[] issues1 = new DataTreeIssue[] { new DataTreeIssue("Test Issue") }; + DataTreeIssue[] issues2 = new DataTreeIssue[] { new DataTreeIssue("Test Issue"), new DataTreeIssue("Test Issue2") }; + + Assert.Multiple(() => + { + Assert.That(new DataTree("Test", 3, true, issues1) == new DataTree("Test", 3, true, issues1.ToList().ToArray()), Is.True); + Assert.That(new DataTree("Test", 3, true, issues1) != new DataTree("Test", 3, true, issues1.ToList().ToArray()), Is.False); + Assert.That(new DataTree("Test", 3, true, issues1).Equals(new DataTree("Test", 3, true, issues1.ToList().ToArray())), Is.True); + + Assert.That(new DataTree("Test", 3, true) == new DataTree("Test", 3, true, issues2), Is.False); + Assert.That(new DataTree("Test", 3, true, issues1) == new DataTree("Test", 3, true, issues2), Is.False); + Assert.That(new DataTree("Test", 3, true, issues1) != new DataTree("Test", 3, true, issues2), Is.True); + Assert.That(new DataTree("Test", 3, true, issues1).Equals(new DataTree("Test", 3, true, issues2)), Is.False); + }); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestDataTreeIssue.cs b/RDMSharpTests/Metadata/JSON/TestDataTreeIssue.cs new file mode 100644 index 0000000..e536fdc --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestDataTreeIssue.cs @@ -0,0 +1,21 @@ +using RDMSharp.Metadata; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestDataTreeIssue + { + [Test] + public void TestMany() + { + Assert.Multiple(() => + { + var issue = new DataTreeIssue(); + Assert.That(issue.ToString(), Is.Null); + issue = new DataTreeIssue("Test"); + Assert.That(issue.ToString(), Is.EqualTo("Test")); + Assert.Throws(typeof(ArgumentNullException), () => new DataTreeIssue("")); + Assert.Throws(typeof(ArgumentNullException), () => new DataTreeIssue(null)); + }); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestDefineNotFoundException.cs b/RDMSharpTests/Metadata/JSON/TestDefineNotFoundException.cs new file mode 100644 index 0000000..d2cf3a7 --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestDefineNotFoundException.cs @@ -0,0 +1,19 @@ +using RDMSharp.Metadata; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestDefineNotFoundException + { + [Test] + public void TestMany() + { + Assert.Multiple(() => + { + var exception = new DefineNotFoundException(); + Assert.That(exception.Message, Is.Not.Null); + exception = new DefineNotFoundException("Test"); + Assert.That(exception.Message, Is.EqualTo("Test")); + }); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestIntegerType.cs b/RDMSharpTests/Metadata/JSON/TestIntegerType.cs new file mode 100644 index 0000000..6b2751c --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestIntegerType.cs @@ -0,0 +1,420 @@ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using RDMSharp.Metadata.JSON.OneOfTypes; +using RDMSharp.RDM; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestIntegerType + { + [Test] + public void TestManyInt8() + { + var integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int8, null, null, null, null, null, null); + Assert.That(integerType.Type, Is.EqualTo(EIntegerType.Int8)); + + Assert.DoesNotThrow(() => + { + PDL pdl = integerType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(1)); + }); + + Assert.Throws(typeof(ArgumentException), () => integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)); + + Assert.Multiple(() => + { + DoParseDataTest(integerType, -71, new byte[] { 185 }); + DoParseDataTest(integerType, sbyte.MinValue, new byte[] { 128 }, nameof(sbyte.MinValue)); + DoParseDataTest(integerType, sbyte.MaxValue, new byte[] { 127 }, nameof(sbyte.MaxValue)); + DoParseDataTest(integerType, 0, new byte[] { 0 }, "Zero"); + DoParseDataTest(integerType, 1, new byte[] { 1 }, "One"); + }); + } + [Test] + public void TestManyUInt8() + { + var integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null); + Assert.That(integerType.Type, Is.EqualTo(EIntegerType.UInt8)); + + Assert.DoesNotThrow(() => + { + PDL pdl = integerType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(1)); + }); + + Assert.Throws(typeof(ArgumentException), () => integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int8, null, null, null, null, null, null)); + + Assert.Multiple(() => + { + DoParseDataTest(integerType, 71, new byte[] { 71 }); + DoParseDataTest(integerType, byte.MinValue, new byte[] { 0 }, nameof(byte.MinValue)); + DoParseDataTest(integerType, byte.MaxValue, new byte[] { 255 }, nameof(byte.MaxValue)); + DoParseDataTest(integerType, 0, new byte[] { 0 }, "Zero"); + DoParseDataTest(integerType, 1, new byte[] { 1 }, "One"); + }); + } + [Test] + public void TestManyInt16() + { + var integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int16, null, null, null, null, null, null); + Assert.That(integerType.Type, Is.EqualTo(EIntegerType.Int16)); + + Assert.DoesNotThrow(() => + { + PDL pdl = integerType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(2)); + }); + + Assert.Throws(typeof(ArgumentException), () => integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt16, null, null, null, null, null, null)); + + Assert.Multiple(() => + { + DoParseDataTest(integerType, -13245, new byte[] { 204, 67 }); + DoParseDataTest(integerType, short.MinValue, new byte[] { 128, 0 }, nameof(short.MinValue)); + DoParseDataTest(integerType, short.MaxValue, new byte[] { 127,255 }, nameof(short.MaxValue)); + DoParseDataTest(integerType, 0, new byte[] { 0, 0 }, "Zero"); + DoParseDataTest(integerType, 1, new byte[] { 0, 1 }, "One"); + }); + } + [Test] + public void TestManyUInt16() + { + var integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt16, null, null, null, null, null, null); + Assert.That(integerType.Type, Is.EqualTo(EIntegerType.UInt16)); + + Assert.DoesNotThrow(() => + { + PDL pdl = integerType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(2)); + }); + + Assert.Throws(typeof(ArgumentException), () => integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int16, null, null, null, null, null, null)); + + Assert.Multiple(() => + { + DoParseDataTest(integerType, 65432, new byte[] { 255, 152 }); + DoParseDataTest(integerType, ushort.MinValue, new byte[] { 0, 0 }, nameof(ushort.MinValue)); + DoParseDataTest(integerType, ushort.MaxValue, new byte[] { 255, 255 }, nameof(ushort.MaxValue)); + DoParseDataTest(integerType, 0, new byte[] { 0, 0 }, "Zero"); + DoParseDataTest(integerType, 1, new byte[] { 0, 1 }, "One"); + }); + } + [Test] + public void TestManyInt32() + { + var integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int32, null, null, null, null, null, null); + Assert.That(integerType.Type, Is.EqualTo(EIntegerType.Int32)); + + Assert.DoesNotThrow(() => + { + PDL pdl = integerType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(4)); + }); + + Assert.Throws(typeof(ArgumentException), () => integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt32, null, null, null, null, null, null)); + + Assert.Multiple(() => + { + DoParseDataTest(integerType, -13243567, new byte[] { 255, 53, 235, 81 }); + DoParseDataTest(integerType, int.MinValue, new byte[] { 128, 0, 0, 0 }, nameof(int.MinValue)); + DoParseDataTest(integerType, int.MaxValue, new byte[] { 127, 255, 255, 255 }, nameof(int.MaxValue)); + DoParseDataTest(integerType, 0, new byte[] { 0, 0, 0, 0 }, "Zero"); + DoParseDataTest(integerType, 1, new byte[] { 0, 0, 0, 1 }, "One"); + }); + } + [Test] + public void TestManyUInt32() + { + var integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt32, null, null, null, null, null, null); + Assert.That(integerType.Type, Is.EqualTo(EIntegerType.UInt32)); + + Assert.DoesNotThrow(() => + { + PDL pdl = integerType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(4)); + }); + + Assert.Throws(typeof(ArgumentException), () => integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int32, null, null, null, null, null, null)); + + Assert.Multiple(() => + { + DoParseDataTest(integerType, 75643244, new byte[] { 4, 130, 57, 108 }); + DoParseDataTest(integerType, uint.MinValue, new byte[] { 0, 0, 0, 0 }, nameof(uint.MinValue)); + DoParseDataTest(integerType, uint.MaxValue, new byte[] { 255, 255, 255, 255 }, nameof(uint.MaxValue)); + DoParseDataTest(integerType, 0, new byte[] { 0, 0, 0, 0 }, "Zero"); + DoParseDataTest(integerType, 1, new byte[] { 0, 0, 0, 1 }, "One"); + }); + } + [Test] + public void TestManyInt64() + { + var integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int64, null, null, null, null, null, null); + Assert.That(integerType.Type, Is.EqualTo(EIntegerType.Int64)); + + Assert.DoesNotThrow(() => + { + PDL pdl = integerType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(8)); + }); + + Assert.Throws(typeof(ArgumentException), () => integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt64, null, null, null, null, null, null)); + + Assert.Multiple(() => + { + DoParseDataTest(integerType, -2136456776545, new byte[] { 255, 255, 254, 14, 145, 64, 180, 159 }); + DoParseDataTest(integerType, long.MinValue, new byte[] { 128, 0, 0, 0, 0, 0, 0, 0 }, nameof(long.MinValue)); + DoParseDataTest(integerType, long.MaxValue, new byte[] { 127, 255, 255, 255, 255, 255, 255, 255 }, nameof(long.MaxValue)); + DoParseDataTest(integerType, 0, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, "Zero"); + DoParseDataTest(integerType, 1, new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, "One"); + }); + } + [Test] + public void TestManyUInt64() + { + var integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt64, null, null, null, null, null, null); + Assert.That(integerType.Type, Is.EqualTo(EIntegerType.UInt64)); + + Assert.DoesNotThrow(() => + { + PDL pdl = integerType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(8)); + }); + + Assert.Throws(typeof(ArgumentException), () => integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int64, null, null, null, null, null, null)); + + Assert.Multiple(() => + { + DoParseDataTest(integerType, 345676543456543, new byte[] { 0, 1, 58, 100, 23, 148, 117, 31 }); + DoParseDataTest(integerType, ulong.MinValue, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, nameof(ulong.MinValue)); + DoParseDataTest(integerType, ulong.MaxValue, new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, nameof(ulong.MaxValue)); + DoParseDataTest(integerType, 0, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, "Zero"); + DoParseDataTest(integerType, 1, new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, "One"); + }); + } +#if NET7_0_OR_GREATER + [Test] + public void TestManyInt128() + { + var integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int128, null, null, null, null, null, null); + Assert.That(integerType.Type, Is.EqualTo(EIntegerType.Int128)); + + Assert.DoesNotThrow(() => + { + PDL pdl = integerType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(16)); + }); + + Assert.Throws(typeof(ArgumentException), () => integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt128, null, null, null, null, null, null)); + Assert.Multiple(() => + { + DoParseDataTest(integerType, new Int128(2725151552362626646, 5278987657876567), new byte[] { 37, 209, 174, 229, 253, 173, 190, 86, 0, 18, 193, 54, 24, 31, 20, 87 }); + DoParseDataTest(integerType, Int128.MinValue, new byte[] { 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, nameof(Int128.MinValue)); + DoParseDataTest(integerType, Int128.MaxValue, new byte[] { 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, nameof(Int128.MaxValue)); + DoParseDataTest(integerType, Int128.Zero, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, nameof(Int128.Zero)); + DoParseDataTest(integerType, Int128.One, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, nameof(Int128.One)); + }); + } + [Test] + public void TestManyUInt128() + { + var integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt128, null, null, null, null, null, null); + Assert.That(integerType.Type, Is.EqualTo(EIntegerType.UInt128)); + + Assert.DoesNotThrow(() => + { + PDL pdl = integerType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(16)); + }); + + Assert.Throws(typeof(ArgumentException), () => integerType = new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int128, null, null, null, null, null, null)); + + Assert.Multiple(() => + { + DoParseDataTest(integerType, new UInt128(2725751552362626686, 5278987657876567), new byte[] { 37, 211, 208, 152, 96, 139, 62, 126, 0, 18, 193, 54, 24, 31, 20, 87 }); + DoParseDataTest(integerType, UInt128.MinValue, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, nameof(UInt128.MinValue)); + DoParseDataTest(integerType, UInt128.MaxValue, new byte[] { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, nameof(UInt128.MaxValue)); + DoParseDataTest(integerType, UInt128.Zero, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, nameof(UInt128.Zero)); + DoParseDataTest(integerType, UInt128.One, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, nameof(UInt128.One)); + }); + } +#endif + + [Test] + public void TestPrefix1024() + { + LabeledIntegerType[] labeledIntegerType = new LabeledIntegerType[] { new LabeledIntegerType("Test 0", 0), new LabeledIntegerType("Test 1", 1), new LabeledIntegerType("Test 100", 100), }; + Range[] ranges = new Range[] { new Range(0, 100) }; + CommonPropertiesForNamed[] types = new CommonPropertiesForNamed[] + { + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int8, null, null, null, null, 10, 2), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, 10, 2), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int16, null, null, null, null, 10, 2), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt16, null, null, null, null, 10, 2), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int32, null, null, null, null, 10, 2), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt32, null, null, null, null, 10, 2), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int64, labeledIntegerType, null, ranges, ERDM_SensorUnit.BYTE, 10, 2), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt64, null, null, null, null, 10, 2), + }; + foreach (CommonPropertiesForNamed integerType in types) + { + Assert.That(((IIntegerType)integerType).PrefixBase, Is.EqualTo(2)); + Assert.That(((IIntegerType)integerType).PrefixPower, Is.EqualTo(10)); + Assert.That(((IIntegerType)integerType).PrefixMultiplyer, Is.EqualTo(1024)); + + uint pdl = integerType.GetDataLength().Value.Value; + Assert.Multiple(() => + { + var data = new byte[pdl]; + var dataTree = integerType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo(0)); + var parsedData = integerType.ParsePayloadToData(dataTree); + data = new byte[pdl]; + Assert.That(parsedData, Is.EqualTo(data)); + + data = new byte[pdl]; + data[data.Length - 1] = 1; + dataTree = integerType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo(1024)); + parsedData = integerType.ParsePayloadToData(dataTree); + data = new byte[pdl]; + data[data.Length - 1] = 1; + Assert.That(parsedData, Is.EqualTo(data)); + + data = new byte[pdl]; + data[data.Length - 1] = 100; + dataTree = integerType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo(102400)); + parsedData = integerType.ParsePayloadToData(dataTree); + data = new byte[pdl]; + data[data.Length - 1] = 100; + Assert.That(parsedData, Is.EqualTo(data)); + }); + } + } + [Test] + public void TestPrefix1024Negativ() + { + CommonPropertiesForNamed[] types = new CommonPropertiesForNamed[] + { + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int8, null, null, null, null, 1, -1024), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, 1, -1024), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int16, null, null, null, null, 1, -1024), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt16, null, null, null, null, 1, -1024), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int32, null, null, null, null, 1, -1024), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt32, null, null, null, null, 1, -1024), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int64, null, null, null, null, 1, -1024), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt64, null, null, null, null, 1, -1024), + }; + foreach (CommonPropertiesForNamed integerType in types) + { + Assert.That(((IIntegerType)integerType).PrefixBase, Is.EqualTo(-1024)); + Assert.That(((IIntegerType)integerType).PrefixPower, Is.EqualTo(1)); + Assert.That(((IIntegerType)integerType).PrefixMultiplyer, Is.EqualTo(-1024)); + + uint pdl = integerType.GetDataLength().Value.Value; + Assert.Multiple(() => + { + string message= ((IIntegerType)integerType).Type.ToString(); + var data = new byte[pdl]; + var dataTree = integerType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo(0), message); + var parsedData = integerType.ParsePayloadToData(dataTree); + data = new byte[pdl]; + Assert.That(parsedData, Is.EqualTo(data), message); + + data = new byte[pdl]; + data[data.Length - 1] = 1; + dataTree = integerType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo(-1024), message); + parsedData = integerType.ParsePayloadToData(dataTree); + data = new byte[pdl]; + data[data.Length - 1] = 1; + Assert.That(parsedData, Is.EqualTo(data), message); + + data = new byte[pdl]; + data[data.Length - 1] = 100; + dataTree = integerType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo(-102400), message); + parsedData = integerType.ParsePayloadToData(dataTree); + data = new byte[pdl]; + data[data.Length - 1] = 100; + Assert.That(parsedData, Is.EqualTo(data), message); + }); + } + } + [Test] + public void TestPrefix4Decimals() + { + CommonPropertiesForNamed[] types = new CommonPropertiesForNamed[] + { + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int8, null, null, null, null, -4, 10), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, -4, 10), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int16, null, null, null, null, -4, 10), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt16, null, null, null, null, -4, 10), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int32, null, null, null, null, -4, 10), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt32, null, null, null, null, -4, 10), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.Int64, null, null, null, null, -4, 10), + new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt64, null, null, null, null, -4, 10), + }; + foreach (CommonPropertiesForNamed integerType in types) + { + Assert.That(((IIntegerType)integerType).PrefixBase, Is.EqualTo(10)); + Assert.That(((IIntegerType)integerType).PrefixPower, Is.EqualTo(-4)); + Assert.That(((IIntegerType)integerType).PrefixMultiplyer, Is.EqualTo(0.0001)); + + uint pdl = integerType.GetDataLength().Value.Value; + Assert.Multiple(() => + { + var data = new byte[pdl]; + var dataTree = integerType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo(0)); + var parsedData = integerType.ParsePayloadToData(dataTree); + data = new byte[pdl]; + Assert.That(parsedData, Is.EqualTo(data)); + + data = new byte[pdl]; + data[data.Length - 1] = 1; + dataTree = integerType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo(0.0001)); + parsedData = integerType.ParsePayloadToData(dataTree); + data = new byte[pdl]; + data[data.Length - 1] = 1; + Assert.That(parsedData, Is.EqualTo(data)); + + data = new byte[pdl]; + data[data.Length - 1] = 100; + dataTree = integerType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo(0.01)); + parsedData = integerType.ParsePayloadToData(dataTree); + data = new byte[pdl]; + data[data.Length - 1] = 100; + Assert.That(parsedData, Is.EqualTo(data)); + }); + } + } + + private void DoParseDataTest(IntegerType integerType, T value, byte[] expectedData, string message = null) + { + var dataTree = new DataTree(integerType.Name, 0, value); + var data = new byte[0]; + Assert.DoesNotThrow(() => data = integerType.ParsePayloadToData(dataTree), message); + Assert.That(data, Is.EqualTo(expectedData), message); + + byte[] clonaData = new byte[data.Length]; + Array.Copy(data, clonaData, clonaData.Length); + var parsedDataTree = integerType.ParseDataToPayload(ref clonaData); + Assert.That(clonaData, Has.Length.EqualTo(0), message); + + Assert.That(parsedDataTree, Is.EqualTo(dataTree), message); + + //Test for short Data & PDL Issue + clonaData = new byte[data.Length - 1]; + Array.Copy(data, clonaData, clonaData.Length); + Assert.DoesNotThrow(() => parsedDataTree = integerType.ParseDataToPayload(ref clonaData)); + Assert.That(parsedDataTree.Issues, Is.Not.Null); + Assert.That(parsedDataTree.Value, Is.Not.Null); + + Assert.Throws(typeof(ArithmeticException), () => data = integerType.ParsePayloadToData(new DataTree("Different Name", dataTree.Index, dataTree.Value)), message); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestLabeledBooleanType.cs b/RDMSharpTests/Metadata/JSON/TestLabeledBooleanType.cs new file mode 100644 index 0000000..f509997 --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestLabeledBooleanType.cs @@ -0,0 +1,19 @@ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON.OneOfTypes; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestLabeledBooleanType + { + [Test] + public void TestMany() + { + var labeledBooleanType = new LabeledBooleanType("NAME", "DISPLAY_NAME", "NOTES", null, true); + Assert.That(labeledBooleanType.Value, Is.True); + Assert.Throws(typeof(NotSupportedException), () => labeledBooleanType.GetDataLength()); + byte[] bytes = new byte[0]; + Assert.Throws(typeof(NotSupportedException), () => labeledBooleanType.ParseDataToPayload(ref bytes)); + Assert.Throws(typeof(NotSupportedException), () => labeledBooleanType.ParsePayloadToData(new DataTree())); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestLabeledIntegerType.cs b/RDMSharpTests/Metadata/JSON/TestLabeledIntegerType.cs new file mode 100644 index 0000000..6545873 --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestLabeledIntegerType.cs @@ -0,0 +1,19 @@ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON.OneOfTypes; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestLabeledIntegerType + { + [Test] + public void TestMany() + { + var labeledIntegerType = new LabeledIntegerType("NAME", "DISPLAY_NAME", "NOTES", null, 3); + Assert.That(labeledIntegerType.Value, Is.EqualTo(3)); + Assert.Throws(typeof(NotSupportedException), () => labeledIntegerType.GetDataLength()); + byte[] bytes = new byte[0]; + Assert.Throws(typeof(NotSupportedException), () => labeledIntegerType.ParseDataToPayload(ref bytes)); + Assert.Throws(typeof(NotSupportedException), () => labeledIntegerType.ParsePayloadToData(new DataTree())); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestListType.cs b/RDMSharpTests/Metadata/JSON/TestListType.cs new file mode 100644 index 0000000..1d5295d --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestListType.cs @@ -0,0 +1,126 @@ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON.OneOfTypes; +using RDMSharp.RDM; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestListType + { + [Test] + public void TestMany() + { + var listType = new ListType("NAME", "DISPLAY_NAME", "NOTES", null, "list", new OneOfTypes(new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)), null, null); + Assert.That(listType.MinItems, Is.Null); + Assert.That(listType.MaxItems, Is.Null); + + Assert.DoesNotThrow(() => + { + PDL pdl = listType.GetDataLength(); + Assert.That(pdl.MaxLength, Is.EqualTo(PDL.MAX_LENGTH)); + }); + + Assert.Throws(typeof(ArgumentException), () => listType = new ListType("NAME", "DISPLAY_NAME", "NOTES", null, "lost", new OneOfTypes(new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)), null, null)); + Assert.Throws(typeof(ArgumentException), () => listType = new ListType("NAME", "DISPLAY_NAME", "NOTES", null, "list", new OneOfTypes(), null, null)); + + var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, null, null, 3, 10, null); + listType = new ListType("NAME", "DISPLAY_NAME", "NOTES", null, "list", new OneOfTypes(stringType), 1, 3); + Assert.DoesNotThrow(() => + { + PDL pdl = listType.GetDataLength(); + Assert.That(pdl.Value, Is.Null); + Assert.That(pdl.MinLength, Is.EqualTo(3)); + Assert.That(pdl.MaxLength, Is.EqualTo(30)); + }); + + stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, null, null,32, 32, null); + listType = new ListType("NAME", "DISPLAY_NAME", "NOTES", null, "list", new OneOfTypes(stringType), 1, 3); + Assert.DoesNotThrow(() => + { + PDL pdl = listType.GetDataLength(); + Assert.That(pdl.Value, Is.Null); + Assert.That(pdl.MinLength, Is.EqualTo(32)); + Assert.That(pdl.MaxLength, Is.EqualTo(96)); + }); + + stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, null, null, 32, 32, null); + listType = new ListType("NAME", "DISPLAY_NAME", "NOTES", null, "list", new OneOfTypes(stringType), null, 3); + Assert.DoesNotThrow(() => + { + PDL pdl = listType.GetDataLength(); + Assert.That(pdl.Value, Is.Null); + Assert.That(pdl.MinLength, Is.EqualTo(0)); + Assert.That(pdl.MaxLength, Is.EqualTo(96)); + }); + + stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, null, null, 32, 32, null); + listType = new ListType("NAME", "DISPLAY_NAME", "NOTES", null, "list", new OneOfTypes(stringType), 1, null); + Assert.DoesNotThrow(() => + { + PDL pdl = listType.GetDataLength(); + Assert.That(pdl.Value, Is.Null); + Assert.That(pdl.MinLength, Is.EqualTo(32)); + Assert.That(pdl.MaxLength, Is.EqualTo(PDL.MAX_LENGTH)); + }); + + Assert.Throws(typeof(ArithmeticException), () => listType.validateDataLength(0)); + Assert.Throws(typeof(ArithmeticException), () => listType.validateDataLength(3)); + Assert.DoesNotThrow(() => listType.validateDataLength(32)); + Assert.DoesNotThrow(() => listType.validateDataLength(58905)); + } + + [Test] + public void TestParseData1() + { + var listType = new ListType("NAME", "DISPLAY_NAME", "NOTES", null, "list", new OneOfTypes(new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)), 1, 5); + var dataTree = new DataTree(listType.Name, 0, children: new DataTree[] { new DataTree("NAME", 0, (byte)11), new DataTree("NAME", 1, (byte)22), new DataTree("NAME", 2, (byte)33) }); + var data = listType.ParsePayloadToData(dataTree); + Assert.That(data, Is.EqualTo(new byte[] { 11, 22, 33 })); + + var dataTreeResult = listType.ParseDataToPayload(ref data); + Assert.That(dataTreeResult, Is.EqualTo(dataTree)); + + listType = new ListType("NAME", "DISPLAY_NAME", "NOTES", null, "list", new OneOfTypes(new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)), 3, 3); + data = listType.ParsePayloadToData(dataTree); + Assert.That(data, Is.EqualTo(new byte[] { 11, 22, 33 })); + + dataTreeResult = listType.ParseDataToPayload(ref data); + Assert.That(dataTreeResult, Is.EqualTo(dataTree)); + } + [Test] + public void TestParseDataShortMin() + { + var listType = new ListType("NAME", "DISPLAY_NAME", "NOTES", null, "list", new OneOfTypes(new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)), 4, 5); + var dataTree = new DataTree(listType.Name, 0, children: new DataTree[] { new DataTree("NAME", 0, (byte)11), new DataTree("NAME", 1, (byte)22), new DataTree("NAME", 2, (byte)33) }); + + var data = new byte[] { 11, 22, 33 }; + var dataTreeResult = listType.ParseDataToPayload(ref data); + Assert.That(dataTreeResult.Issues, Has.Length.EqualTo(2)); + } + [Test] + public void TestParseDataExceedMax() + { + var listType = new ListType("NAME", "DISPLAY_NAME", "NOTES", null, "list", new OneOfTypes(new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)), 1, 2); + var dataTree = new DataTree(listType.Name, 0, children: new DataTree[] { new DataTree("NAME", 0, (byte)11), new DataTree("NAME", 1, (byte)22), new DataTree("NAME", 2, (byte)33) }); + + var data = new byte[] { 11, 22, 33 }; + var dataTreeResult = listType.ParseDataToPayload(ref data); + Assert.That(dataTreeResult.Issues, Has.Length.EqualTo(2)); + } + [Test] + public void TestParseDataNameInvalid() + { + var listType = new ListType("NAME", "DISPLAY_NAME", "NOTES", null, "list", new OneOfTypes(new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)), 1, 2); + var dataTree = new DataTree(listType.Name+"INVALID", 0, children: new DataTree[] { new DataTree("NAME", 0, (byte)11), new DataTree("NAME", 1, (byte)22), new DataTree("NAME", 2, (byte)33) }); + + Assert.Throws(typeof(ArithmeticException), () => listType.ParsePayloadToData(dataTree)); + } + [Test] + public void TestParseDataChildNameInvalid() + { + var listType = new ListType("NAME", "DISPLAY_NAME", "NOTES", null, "list", new OneOfTypes(new IntegerType("NAME", "DISPLAY_NAME", "NOTES", null, EIntegerType.UInt8, null, null, null, null, null, null)), 1, 2); + var dataTree = new DataTree(listType.Name, 0, children: new DataTree[] { new DataTree("NAME" + "INVALID", 0, (byte)11), new DataTree("NAME", 1, (byte)22), new DataTree("NAME", 2, (byte)33) }); + + Assert.Throws(typeof(ArithmeticException), () => listType.ParsePayloadToData(dataTree)); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestOneOfTypes.cs b/RDMSharpTests/Metadata/JSON/TestOneOfTypes.cs new file mode 100644 index 0000000..119e648 --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestOneOfTypes.cs @@ -0,0 +1,19 @@ +using RDMSharp.Metadata.JSON.OneOfTypes; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestOneOfTypes + { + [Test] + public void TestMany() + { + var oneOfTypes = new OneOfTypes(); + Assert.That(oneOfTypes.IsEmpty, Is.True); + Assert.That(oneOfTypes.ToString(), Is.Null); + Assert.DoesNotThrow(() => + { + Assert.That(oneOfTypes.GetDataLength().Value, Is.EqualTo(0)); + }); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestPD_EnvelopeType.cs b/RDMSharpTests/Metadata/JSON/TestPD_EnvelopeType.cs new file mode 100644 index 0000000..374cf87 --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestPD_EnvelopeType.cs @@ -0,0 +1,37 @@ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON.OneOfTypes; +using RDMSharp.RDM; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestPD_EnvelopeType + { + [Test] + public void TestMany() + { + var pdEnvelopeType = new PD_EnvelopeType("NAME", "DISPLAY_NAME", "NOTES", null, "pdEnvelope", 2); + Assert.That(pdEnvelopeType.Length, Is.EqualTo(2)); + + Assert.DoesNotThrow(() => + { + PDL pdl = pdEnvelopeType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(2)); + }); + + Assert.Throws(typeof(ArgumentException), () => pdEnvelopeType = new PD_EnvelopeType("NAME", "DISPLAY_NAME", "NOTES", null, "pdEnvelop", 2)); + + } + + [Test] + public void TestParseData1() + { + var pdEnvelopeType = new PD_EnvelopeType("NAME", "DISPLAY_NAME", "NOTES", null, "pdEnvelope", 2); + var dataTree = new DataTree(pdEnvelopeType.Name, 0, null); + var data = pdEnvelopeType.ParsePayloadToData(dataTree); + Assert.That(data, Is.EqualTo(new byte[] { })); + + var dataTreeResult = pdEnvelopeType.ParseDataToPayload(ref data); + Assert.That(dataTreeResult, Is.EqualTo(dataTree)); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestRange.cs b/RDMSharpTests/Metadata/JSON/TestRange.cs new file mode 100644 index 0000000..d9af436 --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestRange.cs @@ -0,0 +1,100 @@ +using RDMSharp.Metadata.JSON; +using RDMSharp.Metadata.JSON.OneOfTypes; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestRange + { + [Test] + public void TestByte() + { + Range range = new Range(1, 7); + Assert.That(range.IsInRange(2), Is.True); + Assert.That(range.IsInRange(0), Is.False); + Assert.That(range.ToString(), Is.EqualTo("Range: 01 - 07")); + } + [Test] + public void TestSByte() + { + Range range = new Range(1, 7); + Assert.That(range.IsInRange(2), Is.True); + Assert.That(range.IsInRange(-3), Is.False); + Assert.That(range.ToString(), Is.EqualTo("Range: 01 - 07")); + } + [Test] + public void TestShort() + { + Range range = new Range(1, 7); + Assert.That(range.IsInRange(2), Is.True); + Assert.That(range.IsInRange(0), Is.False); + Assert.That(range.ToString(), Is.EqualTo("Range: 0001 - 0007")); + } + [Test] + public void TestUShort() + { + Range range = new Range(1, 7); + Assert.That(range.IsInRange(2), Is.True); + Assert.That(range.IsInRange(0), Is.False); + Assert.That(range.ToString(), Is.EqualTo("Range: 0001 - 0007")); + } + [Test] + public void TestInt() + { + Range range = new Range(1, 7); + Assert.That(range.IsInRange(2), Is.True); + Assert.That(range.IsInRange(0), Is.False); + Assert.That(range.ToString(), Is.EqualTo("Range: 00000001 - 00000007")); + } + [Test] + public void TestUInt() + { + Range range = new Range(1, 7); + Assert.That(range.IsInRange(2), Is.True); + Assert.That(range.IsInRange(0), Is.False); + Assert.That(range.ToString(), Is.EqualTo("Range: 00000001 - 00000007")); + } + [Test] + public void TestLong() + { + Range range = new Range(1, 7); + Assert.That(range.IsInRange(2), Is.True); + Assert.That(range.IsInRange(0), Is.False); + Assert.That(range.ToString(), Is.EqualTo("Range: 0000000000000001 - 0000000000000007")); + } + [Test] + public void TestULong() + { + Range range = new Range(1, 7); + Assert.That(range.IsInRange(2), Is.True); + Assert.That(range.IsInRange(0), Is.False); + Assert.That(range.ToString(), Is.EqualTo("Range: 0000000000000001 - 0000000000000007")); + } +#if NET7_0_OR_GREATER + [Test] + public void TestInt128() + { + Range range = new Range(1, 7); + Assert.That(range.IsInRange(2), Is.True); + Assert.That(range.IsInRange(0), Is.False); + Assert.That(range.ToString(), Is.EqualTo("Range: 00000000000000000000000000000001 - 00000000000000000000000000000007")); + } + [Test] + public void TestUInt128() + { + Range range = new Range(1, 7); + Assert.That(range.IsInRange(2), Is.True); + Assert.That(range.IsInRange(0), Is.False); + Assert.That(range.ToString(), Is.EqualTo("Range: 00000000000000000000000000000001 - 00000000000000000000000000000007")); + } +#endif + + [Test] + public void TestStringInvalid() + { + Range range = new Range("1", "7"); + Assert.That(range.IsInRange("2"), Is.False); + Assert.That(range.IsInRange("0"), Is.False); + Assert.That(range.ToString(), Is.EqualTo("Range: 1 - 7")); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestReferenceType.cs b/RDMSharpTests/Metadata/JSON/TestReferenceType.cs new file mode 100644 index 0000000..1fe16b6 --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestReferenceType.cs @@ -0,0 +1,44 @@ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; +using RDMSharp.Metadata.JSON.OneOfTypes; +using RDMSharp.RDM; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestReferenceType + { + [Test] + public void TestMany() + { + var referenceType = new ReferenceType("#/get_request/0"); + Assert.That(referenceType.Command, Is.EqualTo(Command.ECommandDublicte.GetRequest)); + Assert.That(referenceType.Pointer, Is.EqualTo(0)); + + Assert.DoesNotThrow(() => + { + PDL pdl = referenceType.GetDataLength(); + Assert.That(pdl.Value, Is.EqualTo(0)); + Assert.That(pdl.MinLength, Is.Null); + Assert.That(pdl.MaxLength, Is.Null); + }); + + Assert.Throws(typeof(ArgumentException), () => referenceType = new ReferenceType("%/get_request/0")); + } + [Test] + public void TestParse() + { + var referenceType = new ReferenceType("#/get_request/0", new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "uid", null, null)); + Assert.That(referenceType.GetDataLength().Value, Is.EqualTo(6)); + var uid = new UID(0x4646, 0x12345678); + var data = referenceType.ParsePayloadToData(new DataTree(referenceType.ReferencedObject.Name, 0, uid)); + Assert.That(data, Is.EqualTo(new byte[] { 0x46, 0x46, 0x12, 0x34, 0x56, 0x78 })); + var dataTree = referenceType.ParseDataToPayload(ref data); + Assert.That(data, Has.Length.EqualTo(0)); + Assert.That(dataTree.Value, Is.Not.Null); + Assert.That(dataTree.Value, Is.EqualTo(uid)); + + Assert.Throws(typeof(ArithmeticException), () => new BytesType("Other Name", "DISPLAY_NAME", "NOTES", null, "bytes", "uid", null, null).ParsePayloadToData(dataTree)); + Assert.Throws(typeof(ArithmeticException), () => new BytesType("NAME", "DISPLAY_NAME", "NOTES", null, "bytes", "xyz", null, null).ParsePayloadToData(dataTree)); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/JSON/TestStringType.cs b/RDMSharpTests/Metadata/JSON/TestStringType.cs new file mode 100644 index 0000000..bc4aa2b --- /dev/null +++ b/RDMSharpTests/Metadata/JSON/TestStringType.cs @@ -0,0 +1,216 @@ +using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON.OneOfTypes; +using RDMSharp.RDM; +using System.Text; + +namespace RDMSharpTests.Metadata.JSON +{ + public class TestStringType + { + [TearDown] + public void Teardown() + { + Console.OutputEncoding = Encoding.Default; + } + [Test] + public void TestUTF8_Works() + { + Console.OutputEncoding = Encoding.UTF8; + string originalString = "Ä"; + byte[] originalBytes = new byte[] { 195, 132 }; + byte[] byteArray = Encoding.UTF8.GetBytes(originalString); + string resultString = Encoding.UTF8.GetString(byteArray); + byte[] resultByteArray = Encoding.UTF8.GetBytes(originalString); + + + Assert.That(resultString, Is.EqualTo(originalString)); + Assert.That(byteArray, Is.EqualTo(originalBytes)); + Assert.That(resultByteArray, Is.EqualTo(originalBytes)); + } + [Test] + public void TestMany() + { + var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, null, null, null, null, null); + Assert.That(stringType.MinLength, Is.Null); + Assert.That(stringType.MaxLength, Is.Null); + + + Assert.DoesNotThrow(() => + { + PDL pdl = stringType.GetDataLength(); + Assert.That(pdl.Value, Is.Null); + Assert.That(pdl.MinLength, Is.EqualTo(0)); + Assert.That(pdl.MaxLength, Is.EqualTo(PDL.MAX_LENGTH)); + }); + + stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, 1, 32, null, null, null); + Assert.DoesNotThrow(() => + { + PDL pdl = stringType.GetDataLength(); + Assert.That(pdl.Value, Is.Null); + Assert.That(pdl.MinLength, Is.EqualTo(1)); + Assert.That(pdl.MaxLength, Is.EqualTo(32)); + }); + + stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, 1, 32, 0, 34, null); + Assert.DoesNotThrow(() => + { + PDL pdl = stringType.GetDataLength(); + Assert.That(pdl.Value, Is.Null); + Assert.That(pdl.MinLength, Is.EqualTo(0)); + Assert.That(pdl.MaxLength, Is.EqualTo(34)); + }); + + Assert.Throws(typeof(ArgumentException), () => stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "sting", null, null, null, null, null, null, null)); + } + [Test] + public void TestParseFixedLengthASCII() + { + Console.OutputEncoding = Encoding.ASCII; + var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, null, 5, true); + string str = "qwert"; + DataTree dataTree = new DataTree("NAME", 0, str); + byte[] data = stringType.ParsePayloadToData(dataTree); + Assert.That(data, Is.EqualTo(new byte[] { 113, 119, 101, 114, 116 })); + DataTree reverseDataTree = stringType.ParseDataToPayload(ref data); + Assert.Multiple(() => + { + Assert.That(data, Has.Length.Zero); + Assert.That(reverseDataTree, Is.EqualTo(dataTree)); + }); + } + [Test] + public void TestParseFixedLengthInBytesUTF8() + { + Console.OutputEncoding = Encoding.UTF8; + var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, null, null, minBytes: 8, maxBytes: 8, null); + string str = "ÄÜÖß"; + DataTree dataTree = new DataTree("NAME", 0, str); + byte[] data = stringType.ParsePayloadToData(dataTree); + Assert.That(data, Is.EqualTo(new byte[] { 195, 132, 195, 156, 195, 150, 195, 159 })); + DataTree reverseDataTree = stringType.ParseDataToPayload(ref data); + Assert.Multiple(() => + { + Assert.That(data, Has.Length.Zero); + Assert.That(reverseDataTree, Is.EqualTo(dataTree)); + }); + } + [Test] + public void TestParseRangedLengthUTF8() + { + Console.OutputEncoding = Encoding.UTF8; + var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, 4, 6, null, null, null); + string str = "ÄÜÖß"; + DataTree dataTree = new DataTree("NAME", 0, str); + byte[] data = stringType.ParsePayloadToData(dataTree); + Assert.That(data, Is.EqualTo(new byte[] { 195, 132, 195, 156, 195, 150, 195, 159 })); + DataTree reverseDataTree = stringType.ParseDataToPayload(ref data); + Assert.Multiple(() => + { + Assert.That(data, Has.Length.Zero); + Assert.That(reverseDataTree, Is.EqualTo(dataTree)); + }); + } + [Test] + public void TestParseRangedLengthUTF8Mixed() + { + Console.OutputEncoding = Encoding.UTF8; + var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, 4, 6, 4, 8, null); + string str = "ÄUÖS"; + DataTree dataTree = new DataTree("NAME", 0, str); + byte[] data = stringType.ParsePayloadToData(dataTree); + Assert.That(data, Is.EqualTo(new byte[] { 195, 132, 85, 195, 150, 83 })); + DataTree reverseDataTree = stringType.ParseDataToPayload(ref data); + Assert.Multiple(() => + { + Assert.That(data, Has.Length.Zero); + Assert.That(reverseDataTree, Is.EqualTo(dataTree)); + }); + } + + [Test] + public void TestParseExceptions() + { + Console.OutputEncoding = Encoding.UTF8; + var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, 3, 6, 5, 8, null); + string str = "12"; + DataTree dataTree = new DataTree("NAME FAIL", 0, str); + Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree)); + dataTree = new DataTree("NAME", 0, str); + Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree)); + str = "1234"; + dataTree = new DataTree("NAME", 0, str); + Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree)); + str = "1234567"; + dataTree = new DataTree("NAME", 0, str); + Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree)); + + stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, null, null, 5, 8, null); + + str = "ÄÖÜ4567"; + dataTree = new DataTree("NAME", 0, str); + Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree)); + str = "ÄÖÜÜÖÄ"; + dataTree = new DataTree("NAME", 0, str); + Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree)); + str = null; + dataTree = new DataTree("NAME", 0, str); + Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree)); + } + + [Test] + public void TestParseBadFormatedData1() + { + Console.OutputEncoding = Encoding.UTF8; + var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, null, null, 2, 8, null); + byte[] data = new byte[] { 195, 132, 0, 0, 0, 0 }; + var dataTree = stringType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo("Ä")); + Assert.That(dataTree.Issues, Has.Length.EqualTo(1)); + + data = new byte[] { 195, 132, 0, 0, 119, 0 }; + dataTree = stringType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo("Ä")); + Assert.That(dataTree.Issues, Has.Length.EqualTo(2)); + + data = new byte[] { 0, 0, 0, 0, 0, 0 }; + dataTree = stringType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo(string.Empty)); + Assert.That(dataTree.Issues, Has.Length.EqualTo(1)); + + data = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + dataTree = stringType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo(string.Empty)); + Assert.That(dataTree.Issues, Has.Length.EqualTo(2)); + + data = new byte[] { }; + dataTree = stringType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo(string.Empty)); + Assert.That(dataTree.Issues, Has.Length.EqualTo(1)); + + data = new byte[] { 195, 132, 195, 132, 195, 132, 195, 132, 0 }; + dataTree = stringType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo("ÄÄÄÄ")); + Assert.That(dataTree.Issues, Has.Length.EqualTo(1)); + data = new byte[] { 195, 132, 195, 132, 195, 132, 195, 132, 119, 119, 0 }; + dataTree = stringType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo("ÄÄÄÄ")); + Assert.That(dataTree.Issues, Has.Length.EqualTo(1)); + } + [Test] + public void TestParseBadFormatedData2() + { + Console.OutputEncoding = Encoding.UTF8; + var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, 2, 4, null, null, null); + byte[] data = new byte[] { 195, 132, 0, 0, 0, 0 }; + var dataTree = stringType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo("Ä")); + Assert.That(dataTree.Issues, Has.Length.EqualTo(2)); + + data = new byte[] { 195, 132, 119, 119, 119, 119, 0 }; + dataTree = stringType.ParseDataToPayload(ref data); + Assert.That(dataTree.Value, Is.EqualTo("Äwwww")); + Assert.That(dataTree.Issues, Has.Length.EqualTo(1)); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/Parser/TestDefinedDataTreeObjects.cs b/RDMSharpTests/Metadata/Parser/TestDefinedDataTreeObjects.cs new file mode 100644 index 0000000..3916992 --- /dev/null +++ b/RDMSharpTests/Metadata/Parser/TestDefinedDataTreeObjects.cs @@ -0,0 +1,271 @@ +using RDMSharp.Metadata; +using System.Data; +using System.Reflection; +using System.Text; + +namespace RDMSharpTests.Metadata.Parser; + +public class TestDefinedDataTreeObjects +{ + [Test] + public void Test_AllDefinedDataTreeObjectsForValidility() + { + StringBuilder stringBuilder = new StringBuilder(); + foreach (var type in MetadataFactory.DefinedDataTreeObjects) + { + if (type.IsEnum) + continue; + + StringBuilder stringBuilder2 = new StringBuilder(); + + var constructors = type.GetConstructors().Where(c => c.GetCustomAttributes().Count() != 0); + if (constructors.Count() == 0) + stringBuilder2.AppendLine($"{type} not defines a {nameof(DataTreeObjectConstructorAttribute)}"); + + foreach (var constructor in constructors) + { + StringBuilder stringBuilder3 = new StringBuilder(); + var parameters = constructor.GetParameters(); + foreach (var para in parameters.Where(p => !p.GetCustomAttributes().Any(a=>a is DataTreeObjectParameterAttribute))) + stringBuilder3.AppendLine($"\t{para.Name}"); + if (stringBuilder3.Length > 0) + { + stringBuilder2.AppendLine($"{type} Constructor not defines {nameof(DataTreeObjectParameterAttribute)} for the Parameters:"); + stringBuilder2.AppendLine(stringBuilder3.ToString().TrimEnd()); + } + } + if (stringBuilder2.Length > 0) + stringBuilder.AppendLine(stringBuilder2.ToString().Trim()); + } + if (stringBuilder.Length > 0) + Assert.Fail(stringBuilder.ToString().Trim()); + } + + [Test] + public async Task Test_DeviceInfo() + { + byte[] data = { + 0x01, 0x00, 0x00, 0x05, 0x06, 0x01, 0x02, 0x00, + 0x01, 0x01, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, + 0x00, 0x04, 0x00 + }; + + var parameterBag = new ParameterBag(ERDM_Parameter.DEVICE_INFO); + var define = MetadataFactory.GetDefine(parameterBag); + + var dataTreeBranch = MetadataFactory.ParseDataToPayload(define, RDMSharp.Metadata.JSON.Command.ECommandDublicte.GetResponse, data); + + Assert.Multiple(() => + { + Assert.That(dataTreeBranch.IsUnset, Is.False); + Assert.That(dataTreeBranch.IsEmpty, Is.False); + Assert.That(dataTreeBranch.ParsedObject, Is.Not.Null); + Assert.That(dataTreeBranch.ParsedObject, Is.TypeOf(typeof(RDMDeviceInfo))); + + var obj = dataTreeBranch.ParsedObject as RDMDeviceInfo; + Assert.That(obj.RdmProtocolVersionMajor, Is.EqualTo(1)); + Assert.That(obj.RdmProtocolVersionMinor, Is.EqualTo(0)); + Assert.That(obj.DeviceModelId, Is.EqualTo(0x0005)); + Assert.That(obj.ProductCategoryCoarse, Is.EqualTo(ERDM_ProductCategoryCoarse.POWER)); + Assert.That(obj.ProductCategoryFine, Is.EqualTo(ERDM_ProductCategoryFine.POWER_CONTROL)); + Assert.That(obj.SoftwareVersionId, Is.EqualTo(0x02000101)); + Assert.That(obj.Dmx512Footprint, Is.EqualTo(1)); + Assert.That(obj.Dmx512CurrentPersonality, Is.EqualTo(1)); + Assert.That(obj.Dmx512NumberOfPersonalities, Is.EqualTo(3)); + Assert.That(obj.Dmx512StartAddress, Is.EqualTo(1)); + Assert.That(obj.SubDeviceCount, Is.EqualTo(4)); + Assert.That(obj.SensorCount, Is.EqualTo(0)); + }); + + var reversed = DataTreeBranch.FromObject(dataTreeBranch.ParsedObject, null, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.DEVICE_INFO); + Assert.That(reversed, Is.EqualTo(dataTreeBranch)); + } + + [Test] + public async Task Test_Personality() + { + byte[] data = { + 0x01, 0x03 + }; + + var parameterBag = new ParameterBag(ERDM_Parameter.DMX_PERSONALITY); + var define = MetadataFactory.GetDefine(parameterBag); + + var dataTreeBranch = MetadataFactory.ParseDataToPayload(define, RDMSharp.Metadata.JSON.Command.ECommandDublicte.GetResponse, data); + + Assert.Multiple(() => + { + Assert.That(dataTreeBranch.IsUnset, Is.False); + Assert.That(dataTreeBranch.IsEmpty, Is.False); + Assert.That(dataTreeBranch.ParsedObject, Is.Not.Null); + Assert.That(dataTreeBranch.ParsedObject, Is.TypeOf(typeof(RDMDMXPersonality))); + + var obj = dataTreeBranch.ParsedObject as RDMDMXPersonality; + Assert.That(obj.CurrentPersonality, Is.EqualTo(1)); + Assert.That(obj.OfPersonalities, Is.EqualTo(3)); + }); + + var reversed = DataTreeBranch.FromObject(dataTreeBranch.ParsedObject, null, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.DMX_PERSONALITY); + Assert.That(reversed, Is.EqualTo(dataTreeBranch)); + } + + [Test] + public async Task Test_Personality_Description() + { + byte[] data = { + 0x01, 0x00, 0x01, 0x53, 0x45, 0x51, 0x55, 0x45, + 0x4e, 0x43, 0x45 + }; + + var parameterBag = new ParameterBag(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION); + var define = MetadataFactory.GetDefine(parameterBag); + + var dataTreeBranch = MetadataFactory.ParseDataToPayload(define, RDMSharp.Metadata.JSON.Command.ECommandDublicte.GetResponse, data); + + Assert.Multiple(() => + { + Assert.That(dataTreeBranch.IsUnset, Is.False); + Assert.That(dataTreeBranch.IsEmpty, Is.False); + Assert.That(dataTreeBranch.ParsedObject, Is.Not.Null); + Assert.That(dataTreeBranch.ParsedObject, Is.TypeOf(typeof(RDMDMXPersonalityDescription))); + + var obj = dataTreeBranch.ParsedObject as RDMDMXPersonalityDescription; + Assert.That(obj.PersonalityId, Is.EqualTo(1)); + Assert.That(obj.Slots, Is.EqualTo(1)); + Assert.That(obj.Description, Is.EqualTo("SEQUENCE")); + }); + + var reversed = DataTreeBranch.FromObject(dataTreeBranch.ParsedObject, null, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION); + Assert.That(reversed, Is.EqualTo(dataTreeBranch)); + } + + [Test] + public async Task Test_Slot_Description() + { + byte[] data = { + 0x00, 0x00, 0x53, 0x41, 0x46, 0x45, 0x54, 0x59 + }; + + var parameterBag = new ParameterBag(ERDM_Parameter.SLOT_DESCRIPTION); + var define = MetadataFactory.GetDefine(parameterBag); + + var dataTreeBranch = MetadataFactory.ParseDataToPayload(define, RDMSharp.Metadata.JSON.Command.ECommandDublicte.GetResponse, data); + + Assert.Multiple(() => + { + Assert.That(dataTreeBranch.IsUnset, Is.False); + Assert.That(dataTreeBranch.IsEmpty, Is.False); + Assert.That(dataTreeBranch.ParsedObject, Is.Not.Null); + Assert.That(dataTreeBranch.ParsedObject, Is.TypeOf(typeof(RDMSlotDescription))); + + var obj = dataTreeBranch.ParsedObject as RDMSlotDescription; + Assert.That(obj.SlotId, Is.EqualTo(0)); + Assert.That(obj.Description, Is.EqualTo("SAFETY")); + }); + + var reversed = DataTreeBranch.FromObject(dataTreeBranch.ParsedObject, null, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.SLOT_DESCRIPTION); + Assert.That(reversed, Is.EqualTo(dataTreeBranch)); + } + [Test] + public async Task Test_Slot_Info() + { + byte[] data = { + 0,0,0,0,1, + 0,1,0,4,4, + 0,2,0,2,5, + 0,3,0,2,6, + 0,4,0,2,7 + }; + + var parameterBag = new ParameterBag(ERDM_Parameter.SLOT_INFO); + var define = MetadataFactory.GetDefine(parameterBag); + + var dataTreeBranch = MetadataFactory.ParseDataToPayload(define, RDMSharp.Metadata.JSON.Command.ECommandDublicte.GetResponse, data); + + Assert.Multiple(() => + { + Assert.That(dataTreeBranch.IsUnset, Is.False); + Assert.That(dataTreeBranch.IsEmpty, Is.False); + Assert.That(dataTreeBranch.ParsedObject, Is.Not.Null); + Assert.That(dataTreeBranch.ParsedObject, Is.TypeOf(typeof(RDMSlotInfo[]))); + + var obj = dataTreeBranch.ParsedObject as RDMSlotInfo[]; + Assert.That(obj[0].SlotOffset, Is.EqualTo(0)); + Assert.That(obj[0].SlotType, Is.EqualTo(ERDM_SlotType.PRIMARY)); + Assert.That(obj[0].SlotLabelId, Is.EqualTo(ERDM_SlotCategory.INTENSITY)); + + Assert.That(obj[1].SlotOffset, Is.EqualTo(1)); + Assert.That(obj[1].SlotType, Is.EqualTo(ERDM_SlotType.PRIMARY)); + Assert.That(obj[1].SlotLabelId, Is.EqualTo(ERDM_SlotCategory.STROBE)); + + Assert.That(obj[2].SlotOffset, Is.EqualTo(2)); + Assert.That(obj[2].SlotType, Is.EqualTo(ERDM_SlotType.PRIMARY)); + Assert.That(obj[2].SlotLabelId, Is.EqualTo(ERDM_SlotCategory.COLOR_ADD_RED)); + + Assert.That(obj[3].SlotOffset, Is.EqualTo(3)); + Assert.That(obj[3].SlotType, Is.EqualTo(ERDM_SlotType.PRIMARY)); + Assert.That(obj[3].SlotLabelId, Is.EqualTo(ERDM_SlotCategory.COLOR_ADD_GREEN)); + + Assert.That(obj[4].SlotOffset, Is.EqualTo(4)); + Assert.That(obj[4].SlotType, Is.EqualTo(ERDM_SlotType.PRIMARY)); + Assert.That(obj[4].SlotLabelId, Is.EqualTo(ERDM_SlotCategory.COLOR_ADD_BLUE)); + }); + + var reversed = DataTreeBranch.FromObject(dataTreeBranch.ParsedObject, null, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.SLOT_INFO); + Assert.That(reversed, Is.EqualTo(dataTreeBranch)); + } + + [Test] + public async Task Test_Display_Invert() + { + byte[] data = { + 0x01 + }; + + var parameterBag = new ParameterBag(ERDM_Parameter.DISPLAY_INVERT); + var define = MetadataFactory.GetDefine(parameterBag); + + var dataTreeBranch = MetadataFactory.ParseDataToPayload(define, RDMSharp.Metadata.JSON.Command.ECommandDublicte.SetRequest, data); + + Assert.Multiple(() => + { + Assert.That(dataTreeBranch.IsUnset, Is.False); + Assert.That(dataTreeBranch.IsEmpty, Is.False); + Assert.That(dataTreeBranch.ParsedObject, Is.Not.Null); + Assert.That(dataTreeBranch.ParsedObject, Is.TypeOf(typeof(ERDM_DisplayInvert))); + + var obj = (ERDM_DisplayInvert)dataTreeBranch.ParsedObject; + Assert.That(obj, Is.EqualTo(ERDM_DisplayInvert.ON)); + }); + + var reversed = DataTreeBranch.FromObject(dataTreeBranch.ParsedObject, null, ERDM_Command.SET_COMMAND, ERDM_Parameter.DISPLAY_INVERT); + Assert.That(reversed, Is.EqualTo(dataTreeBranch)); + } + + [Test] + public async Task Test_Status_Messages() + { + byte[] data = { + 0x02 + }; + + var parameterBag = new ParameterBag(ERDM_Parameter.STATUS_MESSAGES); + var define = MetadataFactory.GetDefine(parameterBag); + + var dataTreeBranch = MetadataFactory.ParseDataToPayload(define, RDMSharp.Metadata.JSON.Command.ECommandDublicte.GetRequest, data); + + Assert.Multiple(() => + { + Assert.That(dataTreeBranch.IsUnset, Is.False); + Assert.That(dataTreeBranch.IsEmpty, Is.False); + Assert.That(dataTreeBranch.ParsedObject, Is.Not.Null); + Assert.That(dataTreeBranch.ParsedObject, Is.TypeOf(typeof(ERDM_Status))); + + var obj = (ERDM_Status)dataTreeBranch.ParsedObject; + Assert.That(obj, Is.EqualTo(ERDM_Status.ADVISORY)); + }); + + var reversed = DataTreeBranch.FromObject(dataTreeBranch.ParsedObject, null, ERDM_Command.GET_COMMAND, ERDM_Parameter.STATUS_MESSAGES); + Assert.That(reversed, Is.EqualTo(dataTreeBranch)); + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/TestMetadataFactoryStuff.cs b/RDMSharpTests/Metadata/TestMetadataFactoryStuff.cs new file mode 100644 index 0000000..c318669 --- /dev/null +++ b/RDMSharpTests/Metadata/TestMetadataFactoryStuff.cs @@ -0,0 +1,63 @@ +using RDMSharp.Metadata; + +namespace RDMSharpTests.Metadata +{ + public class TestMetadataFactoryStuff + { + [SetUp] + public void Setup() + { + Console.OutputEncoding = System.Text.Encoding.Unicode; + } + [TearDown] + public void Teardown() + { + Console.OutputEncoding = System.Text.Encoding.Default; + } + + //[Test] + //public void TestMetadataFactory() + //{ + // var schemas = MetadataFactory.GetMetadataSchemaVersions(); + // Assert.That(schemas, Has.Count.EqualTo(1)); + // var defines = MetadataFactory.GetMetadataDefineVersions(); + // Assert.That(defines, Has.Count.EqualTo(122)); + // foreach (var define in defines) + // testString(define.ToString()); + //} + + [Test] + public void TestMetadataVersion() + { + var mv = new MetadataVersion("RDMSharp.Resources.JSON_Defines._1._0._0.Defines.e1._20.BOOT_SOFTWARE_VERSION_ID.json"); + testString(mv.ToString()); + Assert.Multiple(() => + { + Assert.Throws(typeof(ArgumentNullException), () => MetadataVersion.getVersion(null)); + Assert.Throws(typeof(ArgumentNullException), () => MetadataVersion.getName(null)); + Assert.Throws(typeof(ArgumentNullException), () => MetadataVersion.getIsSchema(null)); + + Assert.Throws(typeof(FormatException), () => MetadataVersion.getVersion("RDMSharp.Resources.JSON_Defines.1.0.0.Defines.e1._20.BOOT_SOFTWARE_VERSION_ID.json")); + Assert.Throws(typeof(FormatException), () => MetadataVersion.getVersion("RDMSharp.Resources.JSON_Defines._1._X._0.Defines.e1._20.BOOT_SOFTWARE_VERSION_ID.json")); + Assert.Throws(typeof(ArgumentException), () => MetadataVersion.getVersion("RDMSharp.Resources.JSON_Defines._1._0._0.Defines.e1._20.BOOT_SOFTWARE_VERSION_ID.jsan")); + Assert.Throws(typeof(FormatException), () => MetadataVersion.getName("RDMSharp.Resources.JSON_Defines._1._0._0.Defines.e1._20.BOOT_SOFTWARE_VERSION_ID.jsan")); + Assert.Throws(typeof(ArgumentException), () => MetadataVersion.getIsSchema("RDMSharp.Resources.JSON_Defines._1._0._0.Defines.e1._20.BOOT_SOFTWARE_VERSION_ID.jsan")); + }); + } + + [Test] + public void TestMetadataBag() + { + var bag = new MetadataBag("1.0.2", "NAME.json", false, "content", "Path"); + testString(bag.ToString()); + Assert.Throws(typeof(ArgumentNullException), () => MetadataBag.getContent(null)); + } + static void testString(string str) + { + Assert.That(str, Is.Not.WhiteSpace); + Assert.That(str, Is.Not.Empty); + Assert.That(str, Does.Not.Contain("{")); + Assert.That(str, Does.Not.Contain("}")); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/TestParameterBag.cs b/RDMSharpTests/Metadata/TestParameterBag.cs new file mode 100644 index 0000000..bb49cc0 --- /dev/null +++ b/RDMSharpTests/Metadata/TestParameterBag.cs @@ -0,0 +1,99 @@ +using RDMSharp.Metadata; + +namespace RDMSharpTests.Metadata +{ + public class TestParameterBag + { + + [Test] + public void TestMany() + { + Assert.Throws(typeof(NotSupportedException), () => new ParameterBag()); + HashSet parameterBags = new HashSet(); + Assert.DoesNotThrow(() => parameterBags.Add(new ParameterBag(ERDM_Parameter.CURVE))); + + + ERDM_Parameter pid = ERDM_Parameter.ADD_TAG; + ParameterBag bag = new ParameterBag(pid); + parameterBags.Add(bag); + Assert.Multiple(() => + { + Assert.That(bag, Is.Not.Default); + Assert.That(bag.PID, Is.EqualTo(pid)); + Assert.That(bag.ManufacturerID, Is.EqualTo(0)); + Assert.That(bag.DeviceModelID, Is.EqualTo(null)); + Assert.That(bag.SoftwareVersionID, Is.EqualTo(null)); + Assert.That(bag.ToString(), Is.EqualTo(pid.ToString())); + }); + + pid = (ERDM_Parameter)0x8943; + bag = new ParameterBag(pid, 432, 678, 42); + parameterBags.Add(bag); + Assert.Multiple(() => + { + Assert.That(bag, Is.Not.Default); + Assert.That(bag.PID, Is.EqualTo(pid)); + Assert.That(bag.ManufacturerID, Is.EqualTo(432)); + Assert.That(bag.DeviceModelID, Is.EqualTo(678)); + Assert.That(bag.SoftwareVersionID, Is.EqualTo(42)); + Assert.That(bag.ToString(), Is.EqualTo($"{pid} ManufacturerID: {432}, DeviceModelID: {678}, SoftwareVersionID: {42}")); + }); + + bag = new ParameterBag(pid, 432, 678); + parameterBags.Add(bag); + Assert.Multiple(() => + { + Assert.That(bag, Is.Not.Default); + Assert.That(bag.PID, Is.EqualTo(pid)); + Assert.That(bag.ManufacturerID, Is.EqualTo(432)); + Assert.That(bag.DeviceModelID, Is.EqualTo(678)); + Assert.That(bag.SoftwareVersionID, Is.EqualTo(null)); + Assert.That(bag.ToString(), Is.EqualTo($"{pid} ManufacturerID: {432}, DeviceModelID: {678}")); + }); + + bag = new ParameterBag(pid, 432); + parameterBags.Add(bag); + Assert.Multiple(() => + { + Assert.That(bag, Is.Not.Default); + Assert.That(bag.PID, Is.EqualTo(pid)); + Assert.That(bag.ManufacturerID, Is.EqualTo(432)); + Assert.That(bag.DeviceModelID, Is.EqualTo(null)); + Assert.That(bag.SoftwareVersionID, Is.EqualTo(null)); + Assert.That(bag.ToString(), Is.EqualTo($"{pid} ManufacturerID: {432}")); + }); + + Assert.Throws(typeof(ArgumentNullException), () => new ParameterBag(pid)); + } + + + [Test] + public void TestEqualMethodes() + { + Assert.Multiple(() => + { + Assert.That(new ParameterBag(ERDM_Parameter.CURVE) == new ParameterBag(ERDM_Parameter.CURVE), Is.True); + Assert.That(new ParameterBag(ERDM_Parameter.CURVE) == new ParameterBag(ERDM_Parameter.DIMMER_INFO), Is.False); + + Assert.That(new ParameterBag(ERDM_Parameter.CURVE) != new ParameterBag(ERDM_Parameter.CURVE), Is.False); + Assert.That(new ParameterBag(ERDM_Parameter.CURVE) != new ParameterBag(ERDM_Parameter.DIMMER_INFO), Is.True); + + Assert.That(new ParameterBag(ERDM_Parameter.CURVE).Equals(new ParameterBag(ERDM_Parameter.CURVE)), Is.True); + Assert.That(new ParameterBag(ERDM_Parameter.CURVE).Equals(new ParameterBag(ERDM_Parameter.DIMMER_INFO)), Is.False); + + Assert.That(new ParameterBag(ERDM_Parameter.CURVE).Equals((object)new ParameterBag(ERDM_Parameter.CURVE)), Is.True); + Assert.That(new ParameterBag(ERDM_Parameter.CURVE).Equals((object)new ParameterBag(ERDM_Parameter.DIMMER_INFO)), Is.False); + + Assert.That(new ParameterBag(ERDM_Parameter.CURVE).Equals(null), Is.False); + + ERDM_Parameter pid = (ERDM_Parameter)0x8555; + Assert.That(new ParameterBag(pid, 1), Is.Not.EqualTo(new ParameterBag(pid, 2))); + Assert.That(new ParameterBag(pid, 1), Is.Not.EqualTo(new ParameterBag(pid, 1, 444))); + Assert.That(new ParameterBag(pid, 1, 444), Is.Not.EqualTo(new ParameterBag(pid, 1, 444, 5))); +#pragma warning disable NUnit2009 + Assert.That(new ParameterBag(pid, 1, 444, 5), Is.EqualTo(new ParameterBag(pid, 1, 444, 5))); +#pragma warning restore NUnit2009 + }); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Metadata/TestPeerToPeerProcess.cs b/RDMSharpTests/Metadata/TestPeerToPeerProcess.cs new file mode 100644 index 0000000..93c2489 --- /dev/null +++ b/RDMSharpTests/Metadata/TestPeerToPeerProcess.cs @@ -0,0 +1,181 @@ +using RDMSharp.Metadata; + +namespace RDMSharpTests.Metadata +{ + public class TestPeerToPeerProcess + { + + [Test] + public async Task Test_Get_DMX_START_ADDRESS() + { + var command = ERDM_Command.GET_COMMAND; + var uid = new UID(1234, 123456); + var subdevice = SubDevice.Root; + var parameterBag = new ParameterBag(ERDM_Parameter.DMX_START_ADDRESS); + const ushort DMX_ADDRESS = 33; + PeerToPeerProcess peerToPeerProcess = new PeerToPeerProcess(command, uid, subdevice, parameterBag); + + Assert.That(peerToPeerProcess.Define, Is.Not.Null); + Assert.That(peerToPeerProcess.State, Is.EqualTo(PeerToPeerProcess.EPeerToPeerProcessState.Waiting)); + Assert.That(peerToPeerProcess.RequestPayloadObject.IsUnset, Is.True); + Assert.That(peerToPeerProcess.ResponsePayloadObject.IsUnset, Is.True); + + AsyncRDMRequestHelper helper = null; + helper = new AsyncRDMRequestHelper(sendMessage); + + await Task.WhenAny( + peerToPeerProcess.Run(helper), + Task.Run(async () => + { + while (peerToPeerProcess.State == PeerToPeerProcess.EPeerToPeerProcessState.Running) + await Task.Delay(100); + })); + + Assert.That(peerToPeerProcess.ResponsePayloadObject, Is.TypeOf(typeof(DataTreeBranch))); + Assert.That(peerToPeerProcess.ResponsePayloadObject.Children[0].Value, Is.EqualTo(DMX_ADDRESS)); + Assert.That(peerToPeerProcess.ResponsePayloadObject.ParsedObject, Is.EqualTo(DMX_ADDRESS)); + + async Task sendMessage(RDMMessage message) + { + Assert.That(message.Command, Is.EqualTo(command)); + Assert.That(message.DestUID, Is.EqualTo(uid)); + Assert.That(message.SubDevice, Is.EqualTo(subdevice)); + Assert.That(message.Parameter, Is.EqualTo(parameterBag.PID)); + + RDMMessage response = new RDMMessage() + { + Command = message.Command | ERDM_Command.RESPONSE, + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + SubDevice = message.SubDevice, + ParameterData = MetadataFactory.GetResponseMessageData(parameterBag, new DataTreeBranch(new DataTree[] { new DataTree("dmx_address", 0, DMX_ADDRESS) })) + }; + + await Task.Delay(10); + helper.ReceiveMessage(response); + } + } + + + [Test] + public async Task Test_Get_PROXIED_DEVICES() + { + var command = ERDM_Command.GET_COMMAND; + var uid = new UID(1234, 123456); + var subdevice = SubDevice.Root; + var parameterBag = new ParameterBag(ERDM_Parameter.PROXIED_DEVICES); + DataTree[] children = new DataTree[500]; + Random rnd = new Random(); + for (int i = 0; i < children.Length; i++) + children[i] = new DataTree("device_uid", (uint)i, new UID(0x1234, (uint)rnd.Next(1, int.MaxValue))); + + PeerToPeerProcess peerToPeerProcess = new PeerToPeerProcess(command, uid, subdevice, parameterBag); + + Assert.That(peerToPeerProcess.Define, Is.Not.Null); + Assert.That(peerToPeerProcess.State, Is.EqualTo(PeerToPeerProcess.EPeerToPeerProcessState.Waiting)); + Assert.That(peerToPeerProcess.RequestPayloadObject.IsUnset, Is.True); + Assert.That(peerToPeerProcess.ResponsePayloadObject.IsUnset, Is.True); + + AsyncRDMRequestHelper helper = null; + byte[] parameterData = MetadataFactory.GetResponseMessageData(parameterBag, new DataTreeBranch(new DataTree[] { new DataTree("device_uids", 0, children: children) })); + helper = new AsyncRDMRequestHelper(sendMessage); + + await Task.WhenAny( + peerToPeerProcess.Run(helper), + Task.Run(async () => + { + while (peerToPeerProcess.State == PeerToPeerProcess.EPeerToPeerProcessState.Running) + await Task.Delay(100); + })); + + Assert.That(peerToPeerProcess.ResponsePayloadObject, Is.TypeOf(typeof(DataTreeBranch))); + Assert.That(peerToPeerProcess.ResponsePayloadObject.Children[0].Children, Is.EqualTo(children)); + Assert.That(peerToPeerProcess.ResponsePayloadObject.ParsedObject, Is.EqualTo(children.Select(dt => dt.Value).ToList())); + + + async Task sendMessage(RDMMessage message) + { + Assert.That(message.Command, Is.EqualTo(command)); + Assert.That(message.DestUID, Is.EqualTo(uid)); + Assert.That(message.SubDevice, Is.EqualTo(subdevice)); + Assert.That(message.Parameter, Is.EqualTo(parameterBag.PID)); + + var count = Math.Min(parameterData.Length, 0xE4); + var _parameterData = parameterData.Take(count).ToArray(); + parameterData= parameterData.Skip(count).ToArray(); + RDMMessage response = new RDMMessage() + { + Command = message.Command | ERDM_Command.RESPONSE, + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + SubDevice = message.SubDevice, + ParameterData = _parameterData, + PortID_or_Responsetype = parameterData.Length == 0 ? (byte)ERDM_ResponseType.ACK : (byte)ERDM_ResponseType.ACK_OVERFLOW + }; + + await Task.Delay(10); + helper.ReceiveMessage(response); + } + } + [Test] + public async Task Test_Get_LAMP_STRIKES() + { + var command = ERDM_Command.GET_COMMAND; + var uid = new UID(1234, 123456); + var subdevice = SubDevice.Root; + var parameterBag = new ParameterBag(ERDM_Parameter.LAMP_STRIKES); + const uint LAMP_STRIKES = 33; + PeerToPeerProcess peerToPeerProcess = new PeerToPeerProcess(command, uid, subdevice, parameterBag); + + Assert.That(peerToPeerProcess.Define, Is.Not.Null); + Assert.That(peerToPeerProcess.State, Is.EqualTo(PeerToPeerProcess.EPeerToPeerProcessState.Waiting)); + Assert.That(peerToPeerProcess.RequestPayloadObject.IsUnset, Is.True); + Assert.That(peerToPeerProcess.ResponsePayloadObject.IsUnset, Is.True); + + AsyncRDMRequestHelper helper = null; + byte count = 0; + helper = new AsyncRDMRequestHelper(sendMessage); + + await Task.WhenAny( + peerToPeerProcess.Run(helper), + Task.Run(async () => + { + while (peerToPeerProcess.State == PeerToPeerProcess.EPeerToPeerProcessState.Running) + await Task.Delay(100); + })); + + Assert.That(peerToPeerProcess.ResponsePayloadObject, Is.TypeOf(typeof(DataTreeBranch))); + Assert.That(peerToPeerProcess.ResponsePayloadObject.Children[0].Value, Is.EqualTo(LAMP_STRIKES)); + Assert.That(peerToPeerProcess.ResponsePayloadObject.ParsedObject, Is.EqualTo(LAMP_STRIKES)); + + async Task sendMessage(RDMMessage message) + { + Assert.That(count, Is.LessThan(2)); + if(count==0) + Assert.That(message.Parameter, Is.EqualTo(parameterBag.PID)); + else if(count==1) + Assert.That(message.Parameter, Is.EqualTo(ERDM_Parameter.QUEUED_MESSAGE)); + Assert.That(message.Command, Is.EqualTo(command)); + Assert.That(message.DestUID, Is.EqualTo(uid)); + Assert.That(message.SubDevice, Is.EqualTo(subdevice)); + + RDMMessage response = new RDMMessage() + { + Command = message.Command | ERDM_Command.RESPONSE, + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = parameterBag.PID, + SubDevice = message.SubDevice, + ParameterData = count == 0 ? new AcknowledgeTimer(TimeSpan.FromSeconds(3)).ToPayloadData() : MetadataFactory.GetResponseMessageData(parameterBag, new DataTreeBranch(new DataTree[] { new DataTree("strikes", 0, LAMP_STRIKES) })), + PortID_or_Responsetype = count == 0 ? (byte)ERDM_ResponseType.ACK_TIMER : (byte)ERDM_ResponseType.ACK + }; + + await Task.Delay(10); + count++; + helper.ReceiveMessage(response); + } + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/RDM/ParameterWrappersTest.cs b/RDMSharpTests/RDM/ParameterWrappersTest.cs deleted file mode 100644 index ab29ac9..0000000 --- a/RDMSharpTests/RDM/ParameterWrappersTest.cs +++ /dev/null @@ -1,660 +0,0 @@ -using RDMSharp.ParameterWrapper; -using RDMSharp.ParameterWrapper.Generic; -using RDMSharp.ParameterWrapper.SGM; -using System.Collections.ObjectModel; - -namespace RDMSharpTests.RDM -{ - public class ParameterWrappersTest - { - private static readonly ERDM_Parameter[] notUsableParameters = new ERDM_Parameter[] - { - ERDM_Parameter.NONE, - ERDM_Parameter.DISC_MUTE, - ERDM_Parameter.DISC_UNIQUE_BRANCH, - ERDM_Parameter.DISC_UN_MUTE - }; - private static readonly ERDM_Parameter[] e1_20Parameters = new ERDM_Parameter[] - { - ERDM_Parameter.PROXIED_DEVICES, - ERDM_Parameter.PROXIED_DEVICES_COUNT, - ERDM_Parameter.COMMS_STATUS, - ERDM_Parameter.QUEUED_MESSAGE, - ERDM_Parameter.STATUS_MESSAGES, - ERDM_Parameter.STATUS_ID_DESCRIPTION, - ERDM_Parameter.CLEAR_STATUS_ID, - ERDM_Parameter.SUB_DEVICE_STATUS_REPORT_THRESHOLD, - ERDM_Parameter.SUPPORTED_PARAMETERS, - ERDM_Parameter.PARAMETER_DESCRIPTION, - ERDM_Parameter.DEVICE_INFO, - ERDM_Parameter.PRODUCT_DETAIL_ID_LIST, - ERDM_Parameter.DEVICE_MODEL_DESCRIPTION, - ERDM_Parameter.MANUFACTURER_LABEL, - ERDM_Parameter.DEVICE_LABEL, - ERDM_Parameter.FACTORY_DEFAULTS, - ERDM_Parameter.LANGUAGE_CAPABILITIES, - ERDM_Parameter.LANGUAGE, - ERDM_Parameter.SOFTWARE_VERSION_LABEL, - ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID, - ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL, - ERDM_Parameter.DMX_PERSONALITY, - ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION, - ERDM_Parameter.DMX_START_ADDRESS, - ERDM_Parameter.SLOT_INFO, - ERDM_Parameter.SLOT_DESCRIPTION, - ERDM_Parameter.DEFAULT_SLOT_VALUE, - ERDM_Parameter.SENSOR_DEFINITION, - ERDM_Parameter.SENSOR_VALUE, - ERDM_Parameter.RECORD_SENSORS, - ERDM_Parameter.DEVICE_HOURS, - ERDM_Parameter.LAMP_HOURS, - ERDM_Parameter.LAMP_STRIKES, - ERDM_Parameter.LAMP_STATE, - ERDM_Parameter.LAMP_ON_MODE, - ERDM_Parameter.DEVICE_POWER_CYCLES, - ERDM_Parameter.DISPLAY_INVERT, - ERDM_Parameter.DISPLAY_LEVEL, - ERDM_Parameter.PAN_INVERT, - ERDM_Parameter.TILT_INVERT, - ERDM_Parameter.PAN_TILT_SWAP, - ERDM_Parameter.REAL_TIME_CLOCK, - ERDM_Parameter.IDENTIFY_DEVICE, - ERDM_Parameter.RESET_DEVICE, - ERDM_Parameter.POWER_STATE, - ERDM_Parameter.PERFORM_SELFTEST, - ERDM_Parameter.SELF_TEST_DESCRIPTION, - ERDM_Parameter.CAPTURE_PRESET, - ERDM_Parameter.PRESET_PLAYBACK - }; - private static readonly ERDM_Parameter[] e1_37_1Parameters = new ERDM_Parameter[] - { - ERDM_Parameter.DMX_BLOCK_ADDRESS, - ERDM_Parameter.DMX_FAIL_MODE, - ERDM_Parameter.DMX_STARTUP_MODE, - ERDM_Parameter.DIMMER_INFO, - ERDM_Parameter.MINIMUM_LEVEL, - ERDM_Parameter.MAXIMUM_LEVEL, - ERDM_Parameter.CURVE, - ERDM_Parameter.CURVE_DESCRIPTION, - ERDM_Parameter.OUTPUT_RESPONSE_TIME, - ERDM_Parameter.OUTPUT_RESPONSE_TIME_DESCRIPTION, - ERDM_Parameter.MODULATION_FREQUENCY, - ERDM_Parameter.MODULATION_FREQUENCY_DESCRIPTION, - ERDM_Parameter.BURN_IN, - ERDM_Parameter.LOCK_PIN, - ERDM_Parameter.LOCK_STATE, - ERDM_Parameter.LOCK_STATE_DESCRIPTION, - ERDM_Parameter.IDENTIFY_MODE, - ERDM_Parameter.PRESET_INFO, - ERDM_Parameter.PRESET_STATUS, - ERDM_Parameter.PRESET_MERGEMODE, - ERDM_Parameter.POWER_ON_SELF_TEST - }; - private static readonly ERDM_Parameter[] e1_37_2Parameters = new ERDM_Parameter[] - { - ERDM_Parameter.LIST_INTERFACES, - ERDM_Parameter.INTERFACE_LABEL, - ERDM_Parameter.INTERFACE_HARDWARE_ADDRESS_TYPE, - ERDM_Parameter.IPV4_DHCP_MODE, - ERDM_Parameter.IPV4_ZEROCONF_MODE, - ERDM_Parameter.IPV4_CURRENT_ADDRESS, - ERDM_Parameter.IPV4_STATIC_ADDRESS, - ERDM_Parameter.INTERFACE_RENEW_DHCP, - ERDM_Parameter.INTERFACE_RELEASE_DHCP, - ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION, - ERDM_Parameter.IPV4_DEFAULT_ROUTE, - ERDM_Parameter.DNS_IPV4_NAME_SERVER, - ERDM_Parameter.DNS_HOSTNAME, - ERDM_Parameter.DNS_DOMAIN_NAME - }; - private static readonly ERDM_Parameter[] e1_37_5Parameters = new ERDM_Parameter[] - { - ERDM_Parameter.MANUFACTURER_URL, - ERDM_Parameter.PRODUCT_URL, - ERDM_Parameter.FIRMWARE_URL, - ERDM_Parameter.SERIAL_NUMBER, - ERDM_Parameter.DEVICE_INFO_OFFSTAGE, - ERDM_Parameter.TEST_DATA, - ERDM_Parameter.COMMS_STATUS_NSC, - ERDM_Parameter.IDENTIFY_TIMEOUT, - ERDM_Parameter.POWER_OFF_READY, - ERDM_Parameter.SHIPPING_LOCK, - ERDM_Parameter.LIST_TAGS, - ERDM_Parameter.ADD_TAG, - ERDM_Parameter.REMOVE_TAG, - ERDM_Parameter.CHECK_TAG, - ERDM_Parameter.CLEAR_TAGS, - ERDM_Parameter.DEVICE_UNIT_NUMBER, - ERDM_Parameter.DMX_PERSONALITY_ID, - ERDM_Parameter.SENSOR_TYPE_CUSTOM, - ERDM_Parameter.SENSOR_UNIT_CUSTOM, - ERDM_Parameter.METADATA_PARAMETER_VERSION, - ERDM_Parameter.METADATA_JSON, - ERDM_Parameter.METADATA_JSON_URL - }; - private static readonly ERDM_Parameter[] e1_37_7Parameters = new ERDM_Parameter[] - { - ERDM_Parameter.ENDPOINT_LIST, - ERDM_Parameter.ENDPOINT_LIST_CHANGE, - ERDM_Parameter.IDENTIFY_ENDPOINT, - ERDM_Parameter.ENDPOINT_TO_UNIVERSE, - ERDM_Parameter.ENDPOINT_MODE, - ERDM_Parameter.ENDPOINT_LABEL, - ERDM_Parameter.RDM_TRAFFIC_ENABLE, - ERDM_Parameter.DISCOVERY_STATE, - ERDM_Parameter.BACKGROUND_DISCOVERY, - ERDM_Parameter.ENDPOINT_TIMING, - ERDM_Parameter.ENDPOINT_TIMING_DESCRIPTION, - ERDM_Parameter.ENDPOINT_RESPONDERS, - ERDM_Parameter.ENDPOINT_RESPONDER_LIST_CHANGE, - ERDM_Parameter.BINDING_CONTROL_FIELDS, - ERDM_Parameter.BACKGROUND_QUEUED_STATUS_POLICY, - ERDM_Parameter.BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION - }; - private static readonly ERDM_Parameter[] e1_33Parameters = new ERDM_Parameter[] - { - ERDM_Parameter.COMPONENT_SCOPE, - ERDM_Parameter.SEARCH_DOMAIN, - ERDM_Parameter.TCP_COMMS_STATUS, - ERDM_Parameter.BROKER_STATUS - }; - private static readonly ERDM_Parameter[] sgmParameters = new ERDM_Parameter[] - { - ERDM_Parameter.SERIAL_NUMBER_SGM, - ERDM_Parameter.REFRESH_RATE, - ERDM_Parameter.DIMMING_CURVE, - ERDM_Parameter.FAN_MODE, - ERDM_Parameter.CRMX_LOG_OFF, - ERDM_Parameter.DIM_MODE, - ERDM_Parameter.INVERT_PIXEL_ORDER, - ERDM_Parameter.NORTH_CALIBRATION, - ERDM_Parameter.BATTERY_EXTENSION, - ERDM_Parameter.SMPS_CALIBRATION, - ERDM_Parameter.WIRELESS_DMX, - ERDM_Parameter.CRMX_BRIDGE_MODE - }; - - private RDMParameterWrapperCatalogueManager manager; - private ERDM_Parameter[] parameters; - private ReadOnlyCollection parameterWrappers; - [SetUp] - public void Setup() - { - manager = RDMParameterWrapperCatalogueManager.GetInstance(); - parameters = (ERDM_Parameter[])Enum.GetValues(typeof(ERDM_Parameter)); - parameterWrappers = manager.ParameterWrappers; - } - - [Test] - public void CheckAllParametersArDefined() - { - var parameterLeft = parameters.Except(e1_20Parameters).Except(e1_37_1Parameters).Except(e1_37_2Parameters).Except(e1_37_5Parameters).Except(e1_37_7Parameters).Except(e1_33Parameters).Except(sgmParameters).ToList(); - - Assert.Multiple(() => - { - Assert.That(parameterLeft, Has.Count.EqualTo(notUsableParameters.Length)); - Assert.That(notUsableParameters.Except(parameterLeft).ToList(), Is.Empty); - }); - } - [Test] - public void CheckE1_20WrappersDefined() - { - var notDefinedParameters = e1_20Parameters.Except(parameterWrappers.Select(pw => pw.Parameter)).ToArray(); - Assert.That(notDefinedParameters, Is.Empty, $"The not defined Parameters:{Environment.NewLine}{ParameterWrappersTest.ParametersToString(notDefinedParameters)}"); - } - [Test] - public void CheckE1_37_1WrappersDefined() - { - var notDefinedParameters = e1_37_1Parameters.Except(parameterWrappers.Select(pw => pw.Parameter)).ToArray(); - Assert.That(notDefinedParameters, Is.Empty, $"The not defined Parameters:{Environment.NewLine}{ParameterWrappersTest.ParametersToString(notDefinedParameters)}"); - } - [Test] - public void CheckE1_37_2WrappersDefined() - { - var notDefinedParameters = e1_37_2Parameters.Except(parameterWrappers.Select(pw => pw.Parameter)).ToArray(); - Assert.That(notDefinedParameters, Is.Empty, $"The not defined Parameters:{Environment.NewLine}{ParameterWrappersTest.ParametersToString(notDefinedParameters)}"); - } - [Test] - public void CheckE1_37_5WrappersDefined() - { - var notDefinedParameters = e1_37_5Parameters.Except(parameterWrappers.Select(pw => pw.Parameter)).ToArray(); - Assert.That(notDefinedParameters, Is.Empty, $"The not defined Parameters:{Environment.NewLine}{ParameterWrappersTest.ParametersToString(notDefinedParameters)}"); - } - [Test] - public void CheckE1_37_7WrappersDefined() - { - var notDefinedParameters = e1_37_7Parameters.Except(parameterWrappers.Select(pw => pw.Parameter)).ToArray(); - Assert.That(notDefinedParameters, Is.Empty, $"The not defined Parameters:{Environment.NewLine}{ParameterWrappersTest.ParametersToString(notDefinedParameters)}"); - } - [Test] - public void CheckE1_33WrappersDefined() - { - var notDefinedParameters = e1_33Parameters.Except(parameterWrappers.Select(pw => pw.Parameter)).ToArray(); - Assert.That(notDefinedParameters, Is.Empty, $"The not defined Parameters:{Environment.NewLine}{ParameterWrappersTest.ParametersToString(notDefinedParameters)}"); - } - - [Test] - public void AssemblyListenerTest() - { - foreach (IRDMParameterWrapper pW in parameterWrappers) - { - Assert.Multiple(() => - { - Assert.That(pW.Name, Does.Not.EndWith(" "), $"{pW.Name} Name is not Vaild"); - Assert.That(pW.Name, Does.Not.StartWith(" "), $"{pW.Name} Name is not Vaild"); - }); - Assert.Multiple(() => - { - Assert.That(pW.Description, Does.Not.EndWith(" "), $"{pW.Name} Description is not Vaild"); - Assert.That(pW.Description, Does.Not.StartWith(" "), $"{pW.Name} Description is not Vaild"); - Assert.That(pW.Description, Does.EndWith("."), $"{pW.Name} Description should end with a \".\""); - }); - var toString = pW.ToString(); - - Assert.Multiple(() => - { - Assert.That(toString, Is.Not.Null); - Assert.That(toString, Does.Not.StartWith("{")); - }); - } - Assert.Multiple(() => - { - foreach (ERDM_Parameter parameter in e1_20Parameters) - Assert.That(parameterWrappers.Where(pw => pw.Parameter == parameter).ToList(), Has.Count.EqualTo(1), $"There are more then one ParameterWrapper for the Parameter: {parameter}"); - - foreach (ERDM_Parameter parameter in e1_37_1Parameters) - Assert.That(parameterWrappers.Where(pw => pw.Parameter == parameter).ToList(), Has.Count.EqualTo(1), $"There are more then one ParameterWrapper for the Parameter: {parameter}"); - - foreach (ERDM_Parameter parameter in e1_37_2Parameters) - Assert.That(parameterWrappers.Where(pw => pw.Parameter == parameter).ToList(), Has.Count.EqualTo(1), $"There are more then one ParameterWrapper for the Parameter: {parameter}"); - - foreach (ERDM_Parameter parameter in e1_37_5Parameters) - Assert.That(parameterWrappers.Where(pw => pw.Parameter == parameter).ToList(), Has.Count.EqualTo(1), $"There are more then one ParameterWrapper for the Parameter: {parameter}"); - - foreach (ERDM_Parameter parameter in e1_37_7Parameters) - Assert.That(parameterWrappers.Where(pw => pw.Parameter == parameter).ToList(), Has.Count.EqualTo(1), $"There are more then one ParameterWrapper for the Parameter: {parameter}"); - - foreach (ERDM_Parameter parameter in e1_33Parameters) - Assert.That(parameterWrappers.Where(pw => pw.Parameter == parameter).ToList(), Has.Count.EqualTo(1), $"There are more then one ParameterWrapper for the Parameter: {parameter}"); - - foreach (ERDM_Parameter parameter in sgmParameters) - Assert.That(parameterWrappers.Where(pw => pw.Parameter == parameter).ToList(), Has.Count.EqualTo(1), $"There are more then one ParameterWrapper for the Parameter: {parameter}"); - }); - Assert.That(e1_20Parameters.Length + e1_37_1Parameters.Length + e1_37_2Parameters.Length + e1_37_5Parameters.Length + e1_37_7Parameters.Length + e1_33Parameters.Length + sgmParameters.Length, Is.EqualTo(parameterWrappers.Count)); - } - [Test] - public void GenericParameterWrapperTestFwBw() - { - List wrappers = new(); - wrappers.Add(new ASCIIParameterWrapper(new RDMParameterDescription(0x1000, 20, ERDM_DataType.ASCII, ERDM_CommandClass.GET | ERDM_CommandClass.SET, description: "ASCII"))); - wrappers.Add(new SignedByteParameterWrapper(new RDMParameterDescription(0x1000, 1, ERDM_DataType.ASCII, ERDM_CommandClass.GET | ERDM_CommandClass.SET, description: "sbyte"))); - wrappers.Add(new UnsignedByteParameterWrapper(new RDMParameterDescription(0x1000, 1, ERDM_DataType.ASCII, ERDM_CommandClass.GET | ERDM_CommandClass.SET, description: "byte"))); - wrappers.Add(new SignedWordParameterWrapper(new RDMParameterDescription(0x1000, 2, ERDM_DataType.ASCII, ERDM_CommandClass.GET | ERDM_CommandClass.SET, description: "short"))); - wrappers.Add(new UnsignedWordParameterWrapper(new RDMParameterDescription(0x1000, 2, ERDM_DataType.ASCII, ERDM_CommandClass.GET | ERDM_CommandClass.SET, description: "ushort"))); - wrappers.Add(new SignedDWordParameterWrapper(new RDMParameterDescription(0x1000, 4, ERDM_DataType.ASCII, ERDM_CommandClass.GET | ERDM_CommandClass.SET, description: "int"))); - wrappers.Add(new UnsignedDWordParameterWrapper(new RDMParameterDescription(0x1000, 4, ERDM_DataType.ASCII, ERDM_CommandClass.GET | ERDM_CommandClass.SET, description: "uint"))); - wrappers.Add(new NotDefinedParameterWrapper(new RDMParameterDescription(0x1000, 20, ERDM_DataType.ASCII, ERDM_CommandClass.GET | ERDM_CommandClass.SET, description: "NotDefined"))); - TestParameterWrapperForwardBackwardSerialization(wrappers); - } - [Test] - public void ParameterWrapperE1_20TestFwBw() - { - TestParameterWrapperForwardBackwardSerialization(e1_20Parameters.Except([ERDM_Parameter.LANGUAGE]).Select(p => manager.GetRDMParameterWrapperByID(p))); - } - [Test] - public void ParameterWrapperE1_33TestFwBw() - { - TestParameterWrapperForwardBackwardSerialization(e1_33Parameters.Select(p => manager.GetRDMParameterWrapperByID(p))); - } - [Test] - public void ParameterWrapperE1_37_1TestFwBw() - { - TestParameterWrapperForwardBackwardSerialization(e1_37_1Parameters.Select(p => manager.GetRDMParameterWrapperByID(p))); - } - [Test] - public void ParameterWrapperE1_37_2TestFwBw() - { - TestParameterWrapperForwardBackwardSerialization(e1_37_2Parameters.Select(p => manager.GetRDMParameterWrapperByID(p))); - } - [Test] - public void ParameterWrapperE1_37_5TestFwBw() - { - TestParameterWrapperForwardBackwardSerialization(e1_37_5Parameters.Select(p => manager.GetRDMParameterWrapperByID(p))); - } - [Test] - public void ParameterWrapperE1_37_7TestFwBw() - { - TestParameterWrapperForwardBackwardSerialization(e1_37_7Parameters.Select(p => manager.GetRDMParameterWrapperByID(p))); - } - [Test] - public void ParameterWrapperSGMTestFwBw() - { - TestParameterWrapperForwardBackwardSerialization(sgmParameters.Select(p => manager.GetRDMParameterWrapperByID(p))); - } - private static void TestParameterWrapperForwardBackwardSerialization(IEnumerable wrappers) - { - Assert.Multiple(() => - { - object value = getValue(null!); - foreach (var wrapper in wrappers) - { - byte tested = 0; - - if (wrapper is IRDMGetParameterWrapperRequest getRequest) - { - tested++; - value = getValue(getRequest.GetRequestType); - Assert.That(value, Is.Not.Null, $"Wrapper {wrapper}"); - value.GetHashCode();//For Coverage; - - var data = getRequest.GetRequestObjectToParameterData(value); - var res = getRequest.GetRequestParameterDataToObject(data); - Assert.That(res, Is.EqualTo(value), $"Wrapper {wrapper}"); - - RDMMessage buildGetRequestMessage = getRequest.BuildGetRequestMessage(value); - Assert.That(buildGetRequestMessage, Is.Not.Null, $"Wrapper {wrapper}"); - } - if (wrapper is IRDMGetParameterWrapperResponse getResponse) - { - tested++; - value = getValue(getResponse.GetResponseType); - Assert.That(value, Is.Not.Null, $"Wrapper {wrapper}"); - value.GetHashCode();//For Coverage; - - var data = getResponse.GetResponseObjectToParameterData(value); - var res = getResponse.GetResponseParameterDataToObject(data); - Assert.That(res, Is.EqualTo(value), $"Wrapper {wrapper}"); - - RDMMessage buildGetResponseMessage = getResponse.BuildGetResponseMessage(value); - Assert.That(buildGetResponseMessage, Is.Not.Null, $"Wrapper {wrapper}"); - } - if (wrapper is IRDMSetParameterWrapperRequest setRequest) - { - tested++; - value = getValue(setRequest.SetRequestType); - Assert.That(value, Is.Not.Null, $"Wrapper {wrapper}"); - value.GetHashCode();//For Coverage; - - var data = setRequest.SetRequestObjectToParameterData(value); - var res = setRequest.SetRequestParameterDataToObject(data); - Assert.That(res, Is.EqualTo(value), $"Wrapper {wrapper}"); - - RDMMessage buildSetRequestMessage = setRequest.BuildSetRequestMessage(value); - Assert.That(buildSetRequestMessage, Is.Not.Null, $"Wrapper {wrapper}"); - } - if (wrapper is IRDMSetParameterWrapperResponse setResponse) - { - tested++; - value = getValue(setResponse.SetResponseType); - Assert.That(value, Is.Not.Null, $"Wrapper {wrapper}"); - value.GetHashCode();//For Coverage; - - var data = setResponse.SetResponseObjectToParameterData(value); - var res = setResponse.SetResponseParameterDataToObject(data); - Assert.That(res, Is.EqualTo(value), $"Wrapper {wrapper}"); - - - RDMMessage buildSetResponseMessage = setResponse.BuildSetResponseMessage(value); - Assert.That(buildSetResponseMessage, Is.Not.Null, $"Wrapper {wrapper}"); - } - if (wrapper is IRDMGetParameterWrapperWithEmptyGetRequest iGetParameterWrapperEmptyRequest) - { - tested++; - RDMMessage buildGetRequestMessage = iGetParameterWrapperEmptyRequest.BuildGetRequestMessage(); - Assert.That(buildGetRequestMessage, Is.Not.Null, $"Wrapper {wrapper}"); - } - if (wrapper is IRDMGetParameterWrapperWithEmptyGetResponse iGetParameterWrapperEmptyResponse) - { - tested++; - RDMMessage buildGetResponseMessage = iGetParameterWrapperEmptyResponse.BuildGetResponseMessage(); - Assert.That(buildGetResponseMessage, Is.Not.Null, $"Wrapper {wrapper}"); - } - if (wrapper is IRDMSetParameterWrapperWithEmptySetRequest iSetParameterWrapperEmptyRequest) - { - tested++; - RDMMessage buildSetRequestMessage = iSetParameterWrapperEmptyRequest.BuildSetRequestMessage(); - Assert.That(buildSetRequestMessage, Is.Not.Null, $"Wrapper {wrapper}"); - } - if (wrapper is IRDMSetParameterWrapperWithEmptySetResponse iSetParameterWrapperEmptyResponse) - { - tested++; - RDMMessage buildSetResponseMessage = iSetParameterWrapperEmptyResponse.BuildSetResponseMessage(); - Assert.That(buildSetResponseMessage, Is.Not.Null, $"Wrapper {wrapper}"); - } - if (wrapper is AbstractRDMParameterWrapper abstractRDMParameterWrapperEmpty4) - { - tested++; - Assert.Throws(typeof(NotSupportedException), () => { abstractRDMParameterWrapperEmpty4.GetRequestObjectToParameterData(null); }); - Assert.Throws(typeof(NotSupportedException), () => { abstractRDMParameterWrapperEmpty4.GetRequestParameterDataToObject(null); }); - - Assert.Throws(typeof(NotSupportedException), () => { abstractRDMParameterWrapperEmpty4.GetResponseObjectToParameterData(null); }); - Assert.Throws(typeof(NotSupportedException), () => { abstractRDMParameterWrapperEmpty4.GetResponseParameterDataToObject(null); }); - - Assert.Throws(typeof(NotSupportedException), () => { abstractRDMParameterWrapperEmpty4.SetRequestObjectToParameterData(null); }); - Assert.Throws(typeof(NotSupportedException), () => { abstractRDMParameterWrapperEmpty4.SetRequestParameterDataToObject(null); }); - - Assert.Throws(typeof(NotSupportedException), () => { abstractRDMParameterWrapperEmpty4.SetResponseObjectToParameterData(null); }); - Assert.Throws(typeof(NotSupportedException), () => { abstractRDMParameterWrapperEmpty4.SetResponseParameterDataToObject(null); }); - } - Assert.That(tested, Is.AtLeast(2), $"At {wrapper}"); - } - - static object getValue(Type type) - { - if (type == typeof(string)) - return "Test String"; - if (type == typeof(bool)) - return true; - if (type == typeof(sbyte)) - return (sbyte)55; - if (type == typeof(byte)) - return (byte)99; - if (type == typeof(short)) - return (short)-0x1234; - if (type == typeof(ushort)) - return (ushort)1523; - if (type == typeof(ushort?)) - return (ushort?)1523; - if (type == typeof(int)) - return (int)-0x123334; - if (type == typeof(uint)) - return (uint)154523; - if (type == typeof(byte[])) - return new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; - if (type == typeof(RDMRealTimeClock)) - return new RDMRealTimeClock(DateTime.Now); - if (type == typeof(RDMDMXPersonality)) - return new RDMDMXPersonality(3, 4); - if (type == typeof(RDMCurve)) - return new RDMCurve(3, 4); - if (type == typeof(RDMPresetPlayback)) - return new RDMPresetPlayback(3, 200); - if (type == typeof(RDMSensorValue)) - return new RDMSensorValue(3, 200); - if (type == typeof(RDMPresetStatus)) - return new RDMPresetStatus(3, 200); - if (type == typeof(RDMCommunicationStatus)) - return new RDMCommunicationStatus(3, 200); - if (type == typeof(RDMDeviceInfo)) - return new RDMDeviceInfo(3, 200); - if (type == typeof(RDMDMXPersonalityDescription)) - return new RDMDMXPersonalityDescription(3, 200); - if (type == typeof(RDMParameterDescription)) - return new RDMParameterDescription(3, 200); - if (type == typeof(RDMProxiedDeviceCount)) - return new RDMProxiedDeviceCount(3); - if (type == typeof(RDMProxiedDevices)) - return new RDMProxiedDevices([new UID((ushort)EManufacturer.Swisson_AG, 1342143), new UID((ushort)EManufacturer.DMXControlProjects_eV, 334412), new UID((ushort)EManufacturer.Martin_Professional_AS, 3123)]); - if (type == typeof(RDMSelfTestDescription)) - return new RDMSelfTestDescription(3); - if (type == typeof(RDMSensorDefinition)) - return new RDMSensorDefinition(3); - if (type == typeof(RDMSlotDescription)) - return new RDMSlotDescription(3); - if (type == typeof(GetBrokerStatusResponse)) - return new GetBrokerStatusResponse(true, ERDM_BrokerStatus.ACTIVE); - if (type == typeof(GetSetComponentScope)) - return new GetSetComponentScope(3, scopeString: "eqadeqew", new IPv4Address(123, 45, 22, 4)); - if (type == typeof(TCPCommsEntry)) - return new TCPCommsEntry("eqadeqew"); - if (type == typeof(RDMCurveDescription)) - return new RDMCurveDescription(3); - if (type == typeof(RDMDimmerInfo)) - return new RDMDimmerInfo(3, 200); - if (type == typeof(RDMDMXBlockAddress)) - return new RDMDMXBlockAddress(3, 200); - if (type == typeof(RDMDMX_xxxx_Mode)) - return new RDMDMX_xxxx_Mode(3, 200); - if (type == typeof(SetLockPinRequest)) - return new SetLockPinRequest(3, 200); - if (type == typeof(RDMLockStateDescription)) - return new RDMLockStateDescription(3); - if (type == typeof(GetLockStateResponse)) - return new GetLockStateResponse(3, 200); - if (type == typeof(RDMMinimumLevel)) - return new RDMMinimumLevel(3, 200); - if (type == typeof(RDMModulationFrequencyDescription)) - return new RDMModulationFrequencyDescription(3, 200); - if (type == typeof(RDMModulationFrequency)) - return new RDMModulationFrequency(3, 200); - if (type == typeof(RDMOutputResponseTimeDescription)) - return new RDMOutputResponseTimeDescription(3); - if (type == typeof(RDMOutputResponseTime)) - return new RDMOutputResponseTime(3, 200); - if (type == typeof(SetLockStateRequest)) - return new SetLockStateRequest(12314, 23); - if (type == typeof(RDMPresetInfo)) - return new RDMPresetInfo(true, true, true, true, true, true, 12354, 21567, 7432, 23467, 7632, 24567, 7532, 23456, ushort.MaxValue, 23456, 6543, ushort.MaxValue, 5432); - if (type == typeof(GetInterfaceListResponse)) - return new GetInterfaceListResponse(new InterfaceDescriptor(1, 444), new InterfaceDescriptor(4, 32)); - if (type == typeof(GetInterfaceNameResponse)) - return new GetInterfaceNameResponse(2, "Test"); - if (type == typeof(GetHardwareAddressResponse)) - return new GetHardwareAddressResponse(9, new MACAddress(12, 34, 56, 88, 55, 32)); - if (type == typeof(GetSetIPV4_xxx_Mode)) - return new GetSetIPV4_xxx_Mode(2, true); - if (type == typeof(GetIPv4CurrentAddressResponse)) - return new GetIPv4CurrentAddressResponse(4, new IPv4Address(123, 45, 22, 4), 12, ERDM_DHCPStatusMode.ACTIVE); - if (type == typeof(GetSetIPv4StaticAddress)) - return new GetSetIPv4StaticAddress(3, new IPv4Address(123, 45, 22, 4), 20); - if (type == typeof(GetSetIPv4DefaultRoute)) - return new GetSetIPv4DefaultRoute(5, new IPv4Address(153, 49, 122, 234)); - if (type == typeof(GetSetIPv4NameServer)) - return new GetSetIPv4NameServer(2, new IPv4Address(123, 45, 22, 4)); - if (type == typeof(GetEndpointListResponse)) - return new GetEndpointListResponse(1, new EndpointDescriptor(4, ERDM_EndpointType.PHYSICAL), new EndpointDescriptor(7, ERDM_EndpointType.VIRTUAL)); - if (type == typeof(GetSetIdentifyEndpoint)) - return new GetSetIdentifyEndpoint(3, true); - if (type == typeof(GetSetEndpointToUniverse)) - return new GetSetEndpointToUniverse(1, 55); - if (type == typeof(GetSetEndpointMode)) - return new GetSetEndpointMode(1, ERDM_EndpointMode.OUTPUT); - if (type == typeof(GetSetEndpointLabel)) - return new GetSetEndpointLabel(3, "Test Endpoint Label"); - if (type == typeof(GetSetEndpointRDMTrafficEnable)) - return new GetSetEndpointRDMTrafficEnable(56, true); - if (type == typeof(GetDiscoveryStateResponse)) - return new GetDiscoveryStateResponse(1, 545, ERDM_DiscoveryState.NOT_ACTIVE); - if (type == typeof(GetSetEndpointBackgroundDiscovery)) - return new GetSetEndpointBackgroundDiscovery(1, true); - if (type == typeof(GetEndpointTimingResponse)) - return new GetEndpointTimingResponse(1, 44, 55); - if (type == typeof(GetEndpointTimingDescriptionResponse)) - return new GetEndpointTimingDescriptionResponse(1, "Test Timing"); - if (type == typeof(GetEndpointRespondersResponse)) - return new GetEndpointRespondersResponse(1, [new UID((ushort)EManufacturer.Swisson_AG, 1342143), new UID((ushort)EManufacturer.DMXControlProjects_eV, 334412), new UID((ushort)EManufacturer.Martin_Professional_AS, 3123)]); - if (type == typeof(GetEndpointResponderListChangeResponse)) - return new GetEndpointResponderListChangeResponse(1, 55); - if (type == typeof(GetBindingAndControlFieldsResponse)) - return new GetBindingAndControlFieldsResponse(1, new UID((ushort)EManufacturer.Swisson_AG, 1342143), 22, new UID((ushort)EManufacturer.Martin_Professional_AS, 3123)); - if (type == typeof(GetBackgroundQueuedStatusPolicyResponse)) - return new GetBackgroundQueuedStatusPolicyResponse(21, 55); - if (type == typeof(GetBackgroundQueuedStatusPolicyDescriptionResponse)) - return new GetBackgroundQueuedStatusPolicyDescriptionResponse(21, "Test QueuedStatusPolicyDescription"); - if (type == typeof(SetDiscoveryStateRequest)) - return new SetDiscoveryStateRequest(22, ERDM_DiscoveryState.INCOMPLETE); - if (type == typeof(SetEndpointTimingRequest)) - return new SetEndpointTimingRequest(22, 34); - if (type == typeof(GetBindingAndControlFieldsRequest)) - return new GetBindingAndControlFieldsRequest(22, new UID((ushort)EManufacturer.Martin_Professional_AS, 3123)); - if (type == typeof(GetDeviceInfoOffstageRequest)) - return new GetDeviceInfoOffstageRequest(23, 3, 1); - if (type == typeof(GetDeviceInfoOffstageResponse)) - return new GetDeviceInfoOffstageResponse(23, 3, 1, (RDMDeviceInfo)getValue(typeof(RDMDeviceInfo))); - if (type == typeof(GetCommunicationStatusNullStartCodeResponse)) - return new GetCommunicationStatusNullStartCodeResponse(23, 3, 1, 3, 2, 99); - if (type == typeof(RDMPersonalityId)) - return new RDMPersonalityId(23, 0x3442, 0x9994); - if (type == typeof(RDMSensorTypeCustomDefine)) - return new RDMSensorTypeCustomDefine(0x99, "Test Sensor Type"); - if (type == typeof(RDMSensorUnitCustomDefine)) - return new RDMSensorUnitCustomDefine(0xee, "~"); - if (type == typeof(RDMMetadataParameterVersion)) - return new RDMMetadataParameterVersion(ERDM_Parameter.BATTERY_EXTENSION, 33); - if (type == typeof(RDMMetadataJson)) - return new RDMMetadataJson(ERDM_Parameter.BATTERY_EXTENSION, "{\r\n \"name\": \"FIRMWARE_URL\",\r\n \"notes\": \"E1.37-5\",\r\n \"manufacturer_id\": 0,\r\n \"pid\": 210,\r\n \"version\": 1,\r\n \"get_request_subdevice_range\": [ \"root\", \"subdevices\" ],\r\n \"get_request\": [],\r\n \"get_response\": [\r\n {\r\n \"name\": \"url\",\r\n \"type\": \"string\",\r\n \"notes\": \"The spec says that the minimum length is 5, but we shouldn't restrict because that would imply we know what the URL scheme is.\",\r\n \"format\": \"url\"\r\n }\r\n ]\r\n}"); - - - - if (type == typeof(ERDM_DisplayInvert)) - return ERDM_DisplayInvert.AUTO; - if (type == typeof(ERDM_LampMode)) - return ERDM_LampMode.ON_MODE_AFTER_CAL; - if (type == typeof(ERDM_LampState)) - return ERDM_LampState.STANDBY; - if (type == typeof(ERDM_IdentifyMode)) - return ERDM_IdentifyMode.LOUD; - if (type == typeof(ERDM_PowerState)) - return ERDM_PowerState.STANDBY; - if (type == typeof(ERDM_ResetType)) - return ERDM_ResetType.Warm; - if (type == typeof(ERDM_Status)) - return ERDM_Status.GET_LAST_MESSAGE; - if (type == typeof(ERDM_MergeMode)) - return ERDM_MergeMode.DMX_ONLY; - if (type == typeof(ERDM_BrokerStatus)) - return ERDM_BrokerStatus.ACTIVE; - if (type == typeof(ERDM_ShippingLockState)) - return ERDM_ShippingLockState.PARTIALLY_LOCKED; - - if (type == typeof(ERDM_Parameter)) - return ERDM_Parameter.LAMP_HOURS; - if (type == typeof(ERDM_Parameter[])) - return e1_20Parameters; - if (type == typeof(RDMStatusMessage[])) - return new RDMStatusMessage[] { new RDMStatusMessage(1, ERDM_Status.ERROR, ERDM_StatusMessage.BREAKER_TRIP), new RDMStatusMessage(1, ERDM_Status.WARNING, ERDM_StatusMessage.WATTS) }; - if (type == typeof(RDMSlotInfo[])) - return new RDMSlotInfo[] { new RDMSlotInfo(1, ERDM_SlotType.PRIMARY, ERDM_SlotCategory.PAN), new RDMSlotInfo(2, ERDM_SlotType.SEC_FINE, ERDM_SlotCategory.PAN), new RDMSlotInfo(3, ERDM_SlotType.PRIMARY, ERDM_SlotCategory.TILT), new RDMSlotInfo(4, ERDM_SlotType.SEC_FINE, ERDM_SlotCategory.TILT) }; - if (type == typeof(ERDM_ProductDetail[])) - return new ERDM_ProductDetail[] { ERDM_ProductDetail.ANALOG_DEMULTIPLEX, ERDM_ProductDetail.BUBBLE, ERDM_ProductDetail.CONFETTI, ERDM_ProductDetail.CO2 }; - if (type == typeof(string[])) - return new string[] { "de", "en", "es" }; - if (type == typeof(RDMDefaultSlotValue[])) - return new RDMDefaultSlotValue[] { new RDMDefaultSlotValue(1, 128), new RDMDefaultSlotValue(2, 12), new RDMDefaultSlotValue(3, 44), }; - - #region SGM - if (type == typeof(RefreshRate)) - return new RefreshRate((byte)34); - if (type == typeof(EDimmingCurve)) - return EDimmingCurve.GAMMA_CORRECTED; - if (type == typeof(EFanMode)) - return EFanMode.HIGH; - if (type == typeof(EDimMode)) - return EDimMode.MAX_POWER; - if (type == typeof(EInvertPixelOrder)) - return EInvertPixelOrder.INVERT; - if (type == typeof(EBatteryExtension)) - return EBatteryExtension._20H; - #endregion - - return null!; - } - }); - } - - private static string ParametersToString(params ERDM_Parameter[] parameters) - { - return String.Join(";", parameters); - } - } -} \ No newline at end of file diff --git a/RDMSharpTests/RDM/PayloadObject/AcknowledgeTimerTest.cs b/RDMSharpTests/RDM/PayloadObject/AcknowledgeTimerTest.cs index 2be1428..49b5ede 100644 --- a/RDMSharpTests/RDM/PayloadObject/AcknowledgeTimerTest.cs +++ b/RDMSharpTests/RDM/PayloadObject/AcknowledgeTimerTest.cs @@ -10,7 +10,7 @@ public void Setup() [Test] public void ToPayloadAndFromMessageTest() { - var time = TimeSpan.FromSeconds(360000); + var time = TimeSpan.FromSeconds(3); AcknowledgeTimer acknowledgeTimer = new AcknowledgeTimer(time); byte[] data = acknowledgeTimer.ToPayloadData(); diff --git a/RDMSharpTests/RDMSharpTests.csproj b/RDMSharpTests/RDMSharpTests.csproj index bcd1ef9..660c5ca 100644 --- a/RDMSharpTests/RDMSharpTests.csproj +++ b/RDMSharpTests/RDMSharpTests.csproj @@ -9,11 +9,10 @@ latest False - - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -23,7 +22,30 @@ - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_128BIT_INTEGER_TEST.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_128BIT_INTEGER_TEST.json new file mode 100644 index 0000000..f82be9e --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_128BIT_INTEGER_TEST.json @@ -0,0 +1,18 @@ +{ + "name": "MOCK_128BIT_INTEGER_TEST", + "manufacturer_id": 4365, + "pid": 4874, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "timeout", + "type": "int128" + }, + { + "name": "timeout", + "type": "uint128" + } + ], + "get_response": "get_request" +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_ALL_INTEGER_TEST_EXCEPT_128BIT.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_ALL_INTEGER_TEST_EXCEPT_128BIT.json new file mode 100644 index 0000000..53d5d10 --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_ALL_INTEGER_TEST_EXCEPT_128BIT.json @@ -0,0 +1,42 @@ +{ + "name": "MOCK_ALL_INTEGER_TEST_EXCEPT_128BIT", + "manufacturer_id": 4365, + "pid": 4874, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "timeout", + "type": "int8" + }, + { + "name": "timeout", + "type": "uint8" + }, + { + "name": "timeout", + "type": "int16" + }, + { + "name": "timeout", + "type": "uint16" + }, + { + "name": "timeout", + "type": "int32" + }, + { + "name": "timeout", + "type": "uint32" + }, + { + "name": "timeout", + "type": "int64" + }, + { + "name": "timeout", + "type": "uint64" + } + ], + "get_response": "get_request" +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_DISPLAY_NAME.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_DISPLAY_NAME.json new file mode 100644 index 0000000..e0f8138 --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_DISPLAY_NAME.json @@ -0,0 +1,62 @@ +{ + "name": "MOCK_DISPLAY_NAME", + "displayName": "Mock Display Name", + "manufacturer_id": 4365, + "pid": 4874, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "timeout", + "displayName": "Timeout", + "type": "uint16", + "units": 21, + "prefixPower": 0, + "labels": [ + { + "name": "Disabled", + "displayName": "Disabled Label", + "value": 0 + } + ] + }, + { + "name": "label", + "displayName": "Label", + "type": "string", + "maxLength": 32, + "restrictToASCII": true + }, + { + "name": "status", + "displayName": "Status", + "type": "boolean" + }, + { + "name": "slots", + "displayName": "Slots", + "type": "list", + "itemType": { + "displayName": "Compound", + "type": "compound", + "subtypes": [ + { + "name": "id", + "type": "uint16" + }, + { + "name": "type", + "type": "uint8" + }, + { + "name": "label_id", + "type": "uint16" + } + ] + }, + "minItems": 2, + "maxItems": 6 + } + ], + "get_response": "get_request" +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_1.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_1.json new file mode 100644 index 0000000..5862d9b --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_1.json @@ -0,0 +1,11 @@ +{ + "name": "MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_1", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { "$ref": "#/set_response/0" } + ] +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_2.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_2.json new file mode 100644 index 0000000..6230687 --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_2.json @@ -0,0 +1,11 @@ +{ + "name": "MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_2", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response": [ + { "$ref": "#/set_request/0" } + ] +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_3.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_3.json new file mode 100644 index 0000000..a591e55 --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_3.json @@ -0,0 +1,11 @@ +{ + "name": "MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_3", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "set_request_subdevice_range": [ "root", "subdevices" ], + "set_request": [], + "set_response": [ + { "$ref": "#/get_response/0" } + ] +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_4.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_4.json new file mode 100644 index 0000000..1cf0087 --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_4.json @@ -0,0 +1,11 @@ +{ + "name": "MOCK_INVALID_BUT_SCHEMA_IS_VALID_REFERENCE_TYPE_NOT_DEFINED_3", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "set_request_subdevice_range": [ "root", "subdevices" ], + "set_request": [], + "set_response": [ + { "$ref": "#/get_request/0" } + ] +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_COMMAND_NUMBER.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_COMMAND_NUMBER.json new file mode 100644 index 0000000..16c77bf --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_COMMAND_NUMBER.json @@ -0,0 +1,9 @@ +{ + "name": "MOCK_INVALID_COMMAND_NUMBER", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": 22, + "get_response": [] +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_ENUM.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_ENUM.json new file mode 100644 index 0000000..21e6a67 --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_ENUM.json @@ -0,0 +1,9 @@ +{ + "name": "MOCK_INVALID_ENUM", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "get_request_subdevice_range": [ "root", "INVALID" ], + "get_request": [], + "get_response": [] +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_NO_GET_PAIR.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_NO_GET_PAIR.json new file mode 100644 index 0000000..694408a --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_NO_GET_PAIR.json @@ -0,0 +1,8 @@ +{ + "name": "MOCK_INVALID_NO_GET_PAIR", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "get_request_subdevice_range": [ "root", 1 ], + "get_request": [] +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_NO_SET_PAIR.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_NO_SET_PAIR.json new file mode 100644 index 0000000..389a86f --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_NO_SET_PAIR.json @@ -0,0 +1,8 @@ +{ + "name": "MOCK_INVALID_NO_SET_PAIR", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "set_request_subdevice_range": [ "root", 1 ], + "set_request": [] +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_ONEOF_TYPE.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_ONEOF_TYPE.json new file mode 100644 index 0000000..12822f6 --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_ONEOF_TYPE.json @@ -0,0 +1,14 @@ +{ + "name": "MOCK_INVALID_ONEOF_TYPE", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "Invalid Type", + "invalid": "invalid" + } + ], + "get_response": [] +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_SUBDEVICE_TYPE_REQUEST.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_SUBDEVICE_TYPE_REQUEST.json new file mode 100644 index 0000000..67b8e77 --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_SUBDEVICE_TYPE_REQUEST.json @@ -0,0 +1,9 @@ +{ + "name": "MOCK_INVALID_SUBDEVICE_TYPE_REQUEST", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "get_request_subdevice_range": [ "root", null, [ 2, 3, 4 ] ], + "get_request": [], + "get_response": [] +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_SUBDEVICE_TYPE_RESPONSE.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_SUBDEVICE_TYPE_RESPONSE.json new file mode 100644 index 0000000..5b5ca98 --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_SUBDEVICE_TYPE_RESPONSE.json @@ -0,0 +1,10 @@ +{ + "name": "MOCK_INVALID_SUBDEVICE_TYPE_RESPONSE", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [], + "get_response_subdevice_range": [ "root", [ 2, 5 ], null ], + "get_response": [] +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_TYPE.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_TYPE.json new file mode 100644 index 0000000..05ac1ef --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_INVALID_TYPE.json @@ -0,0 +1,14 @@ +{ + "name": "MOCK_INVALID_TYPE", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "Invalid Type", + "type": "invalid" + } + ], + "get_response": [] +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_PD_ENVELOPED.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_PD_ENVELOPED.json new file mode 100644 index 0000000..82da703 --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_PD_ENVELOPED.json @@ -0,0 +1,25 @@ +{ + "name": "MOCK_PD_ENVELOPED", + "manufacturer_id": 4365, + "pid": 4874, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "timeout", + "displayName": "Timeout", + "type": "pdEnvelope", + "length": 21 + }, + { + "name": "subdevice_entry", + "type": "pdEnvelope" + }, + { + "name": "entries", + "type": "list", + "itemType": { "type": "pdEnvelope" } + } + ], + "get_response": "get_request" +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_REFERENCE_TYPE.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_REFERENCE_TYPE.json new file mode 100644 index 0000000..9204deb --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_REFERENCE_TYPE.json @@ -0,0 +1,65 @@ +{ + "name": "MOCK_REFERENCE_TYPE", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "root_personality", + "type": "uint8", + "ranges": [ + { + "minimum": 1, + "maximum": 255 + } + ] + }, + { + "name": "subdevice", + "type": "uint16", + "labels": [ + { + "name": "root", + "value": 0 + } + ] + }, + { + "name": "subdevice_personality", + "type": "uint8", + "labels": [ + { + "name": "root", + "value": 0 + } + ] + } + ], + "get_response": [ + { "$ref": "#/set_response/0" } + ], + "set_request": [], + "set_response": [ + { + "name": "root_personality", + "type": "uint8", + "ranges": [ + { + "minimum": 1, + "maximum": 255 + } + ] + }, + { + "name": "subdevice", + "type": "uint16", + "labels": [ + { + "name": "root", + "value": 0 + } + ] + } + ] +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_SINGLE_FIELD.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_SINGLE_FIELD.json new file mode 100644 index 0000000..8db8e8f --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_SINGLE_FIELD.json @@ -0,0 +1,20 @@ +{ + "name": "MOCK_SINGLE_FIELD", + "manufacturer_id": 4365, + "pid": 4874, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": { + "name": "timeout", + "type": "uint16", + "units": 21, + "prefixPower": 0, + "labels": [ + { + "name": "Disabled", + "value": 0 + } + ] + }, + "get_response": "get_request" +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_SINGLE_FIELD_REFERENCE.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_SINGLE_FIELD_REFERENCE.json new file mode 100644 index 0000000..26c7c82 --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_SINGLE_FIELD_REFERENCE.json @@ -0,0 +1,40 @@ +{ + "name": "MOCK_SINGLE_FIELD_REFERENCE", + "manufacturer_id": 4365, + "pid": 4874, + "version": 1, + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ + { + "name": "root_personality", + "type": "uint8", + "ranges": [ + { + "minimum": 1, + "maximum": 255 + } + ] + }, + { + "name": "subdevice", + "type": "uint16", + "labels": [ + { + "name": "root", + "value": 0 + } + ] + }, + { + "name": "subdevice_personality", + "type": "uint8", + "labels": [ + { + "name": "root", + "value": 0 + } + ] + } + ], + "get_response": { "$ref": "#/get_request/0" } +} \ No newline at end of file diff --git a/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_SUBDEVICE_TYPES.json b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_SUBDEVICE_TYPES.json new file mode 100644 index 0000000..61fc0ab --- /dev/null +++ b/RDMSharpTests/Resources/JSON-Defines/1.0.0/Defines/Mocks/MOCK_SUBDEVICE_TYPES.json @@ -0,0 +1,35 @@ +{ + "name": "MOCK_SUBDEVICE_TYPES", + "manufacturer_id": 3456, + "pid": 5678, + "version": 1, + "get_request_subdevice_range": [ + "root", + "subdevices", + 1, + 2, + 3, + 4, + 5, + { + "minimum": 70, + "maximum": 200 + } + ], + "get_request": [], + "get_response_subdevice_range": [ + "root", + "subdevices", + 45, + 75, + 86, + 99, + 23, + { + "minimum": 56, + "maximum": 79 + }, + 256 + ], + "get_response": [] +} \ No newline at end of file diff --git a/RDMSharpTests/TestManyObjects.cs b/RDMSharpTests/TestManyObjects.cs index 8c1b9b9..2af1335 100644 --- a/RDMSharpTests/TestManyObjects.cs +++ b/RDMSharpTests/TestManyObjects.cs @@ -1,3 +1,4 @@ +using RDMSharp.RDM; using System.Collections.Concurrent; using System.Reflection; @@ -245,7 +246,7 @@ public void TestSlot() }); } } - [Test] + [Test] public void TestGeneratedPersonality() { Assert.Throws(typeof(ArgumentOutOfRangeException), () => new GeneratedPersonality(0, "5CH RGB", @@ -284,5 +285,64 @@ public void TestGeneratedPersonality() Assert.That(pers.ID, Is.EqualTo(1)); }); } + [Test] + public void TestPDL() + { + Assert.Multiple(() => + { + PDL pdl = new PDL(); + Assert.That(pdl.Value.HasValue, Is.True); + Assert.That(pdl.MinLength.HasValue, Is.False); + Assert.That(pdl.MaxLength.HasValue, Is.False); + Assert.That(pdl.Value.Value, Is.EqualTo(0)); + + pdl = new PDL(13); + Assert.That(pdl.Value.HasValue, Is.True); + Assert.That(pdl.MinLength.HasValue, Is.False); + Assert.That(pdl.MaxLength.HasValue, Is.False); + Assert.That(pdl.Value.Value, Is.EqualTo(13)); + + + pdl = new PDL(3, 5); + Assert.That(pdl.Value.HasValue, Is.False); + Assert.That(pdl.MinLength.HasValue, Is.True); + Assert.That(pdl.MaxLength.HasValue, Is.True); + Assert.That(pdl.MinLength.Value, Is.EqualTo(3)); + Assert.That(pdl.MaxLength.Value, Is.EqualTo(5)); + + pdl = new PDL(5, 5); + Assert.That(pdl.Value.HasValue, Is.True); + Assert.That(pdl.MinLength.HasValue, Is.False); + Assert.That(pdl.MaxLength.HasValue, Is.False); + Assert.That(pdl.Value.Value, Is.EqualTo(5)); + + + List list = new List(); + list.Add(new PDL(1)); + list.Add(new PDL(2)); + list.Add(new PDL(3)); + pdl = new PDL(list.ToArray()); + Assert.That(pdl.Value.HasValue, Is.True); + Assert.That(pdl.MinLength.HasValue, Is.False); + Assert.That(pdl.MaxLength.HasValue, Is.False); + Assert.That(pdl.Value.Value, Is.EqualTo(6)); + + list.Clear(); + list.Add(new PDL(1, 2)); + list.Add(new PDL(1, 2)); + list.Add(new PDL(3, 4)); + pdl = new PDL(list.ToArray()); + Assert.That(pdl.Value.HasValue, Is.False); + Assert.That(pdl.MinLength.HasValue, Is.True); + Assert.That(pdl.MaxLength.HasValue, Is.True); + Assert.That(pdl.MinLength.Value, Is.EqualTo(5)); + Assert.That(pdl.MaxLength.Value, Is.EqualTo(8)); + + + Assert.Throws(typeof(ArgumentOutOfRangeException), () => new PDL(uint.MaxValue)); + Assert.Throws(typeof(ArgumentOutOfRangeException), () => new PDL(uint.MaxValue, 9)); + Assert.Throws(typeof(ArgumentOutOfRangeException), () => new PDL(1, uint.MaxValue)); + }); + } } } \ No newline at end of file