diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3be5b4e..1bbb4e8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - dotnet-version: [ '7.0', '8.0', '9.0'] + dotnet-version: [ '8.0', '9.0', '10.0'] fail-fast: false runs-on: ${{ matrix.os }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f2fb810..9c11587 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,9 +14,9 @@ jobs: uses: actions/setup-dotnet@v4.2.0 with: dotnet-version: | - 7.0 8.0 9.0 + 10.0 - name: Install dependencies run: dotnet restore - name: Build diff --git a/RDMSharp/Metadata/DataTreeBranch.cs b/RDMSharp/Metadata/DataTreeBranch.cs index 1640740..d0d0aed 100644 --- a/RDMSharp/Metadata/DataTreeBranch.cs +++ b/RDMSharp/Metadata/DataTreeBranch.cs @@ -10,451 +10,469 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("RDMSharpTests")] -namespace RDMSharp.Metadata +namespace RDMSharp.Metadata; + +public readonly struct DataTreeBranch : IEquatable { - public readonly struct DataTreeBranch : IEquatable - { - private static ILogger Logger = Logging.CreateLogger(); - public static readonly DataTreeBranch Empty = new DataTreeBranch(); - public static readonly DataTreeBranch Unset = new DataTreeBranch(true); + private static ILogger Logger = Logging.CreateLogger(); + 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 DataTree[] Children; + public readonly bool IsEmpty; + public readonly bool IsUnset; - public readonly object ParsedObject; - public DataTreeBranch() - { + 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; - } - 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.ECommandDublicate commandType, params DataTree[] children) : this(children) - { - if (define == null) - throw new ArgumentNullException(); + 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.ECommandDublicate commandType, params DataTree[] children) : this(children) + { + if (define == null) + throw new ArgumentNullException(); + try + { ParsedObject = this.getParsedObject(define, commandType); } - - private object getParsedObject(MetadataJSONObjectDefine define, Command.ECommandDublicate commandType) + catch (Exception e) { - ushort pid = define.PID; - var definedDataTreeObjectType = MetadataFactory.GetDefinedDataTreeObjectType(define, commandType); - return getParsedObject(pid, definedDataTreeObjectType, commandType); + Logger?.LogWarning($"Can't get a Parsed Object for {define.Name} (0x{define.PID:X4})", e); } - private object getParsedObject(ushort pid, Type definedDataTreeObjectType, Command.ECommandDublicate commandType) + } + + private object getParsedObject(MetadataJSONObjectDefine define, Command.ECommandDublicate commandType) + { + ushort pid = define.PID; + var definedDataTreeObjectType = MetadataFactory.GetDefinedDataTreeObjectType(define, commandType); + return getParsedObject(pid, definedDataTreeObjectType, commandType); + } + private object getParsedObject(ushort pid, Type definedDataTreeObjectType, Command.ECommandDublicate commandType) + { + if (IsEmpty || IsUnset) + return null; + try { - if (IsEmpty || IsUnset) - return null; - try + if (definedDataTreeObjectType != null) { - if (definedDataTreeObjectType != null) + if (definedDataTreeObjectType.IsEnum) { - if (definedDataTreeObjectType.IsEnum) - { - var enumAttribute = definedDataTreeObjectType.GetCustomAttributes().FirstOrDefault(a => (ushort)a.Parameter == pid && a.Command == commandType); + 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); + 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); + 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) + var children = getChildrenUsingPath(objectAttribute, Children); + DataTree[] getChildrenUsingPath(DataTreeObjectAttribute objectAttribute, DataTree[] children) + { + if (!string.IsNullOrWhiteSpace(objectAttribute.Path)) { - if (!string.IsNullOrWhiteSpace(objectAttribute.Path)) + string[] path = objectAttribute.Path.Split('/'); + while (path.Length >= 1) { - 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(); - } + children = children.FirstOrDefault(c => string.Equals(c.Name, path[0])).Children; + path = path.Skip(1).ToArray(); } - return children; } + return children; + } + + foreach (var constructor in constructors) + { - 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; + } + - if (constructor.GetCustomAttribute() is DataTreeObjectConstructorAttribute cAttribute) + object createObjectFromDataTree(DataTree[] children) { - 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 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) { - 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}'"); + 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; - } + var instance = constructor.Invoke(parameters.ToArray()); + return instance; } } } + } - if (Children.Length == 1) - { - DataTree dataTree = Children[0]; - - if (dataTree.Value != null) - return dataTree.Value; + if (Children.Length == 1) + { + DataTree dataTree = Children[0]; - 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); + if (dataTree.Value != null) + return dataTree.Value; - return array; - } + 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) - { - Logger?.LogError(e); + } + catch (Exception e) + { + Logger?.LogError(e); #pragma warning disable CA2200 - throw e; + throw e; #pragma warning restore CA2200 - } - - throw new NotImplementedException(); } - public static DataTreeBranch FromObject(object obj, object key, ParameterBag parameterBag, ERDM_Command command) + 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 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) { - 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.ECommandDublicate.GetRequest: + case ERDM_Command.GET_COMMAND: + if (define.GetRequest.HasValue) cmd = define.GetRequest; - break; - case Command.ECommandDublicate.GetResponse: + break; + case ERDM_Command.GET_COMMAND_RESPONSE: + if (define.GetResponse.HasValue) cmd = define.GetResponse; - break; - case Command.ECommandDublicate.SetRequest: + break; + case ERDM_Command.SET_COMMAND: + if (define.SetRequest.HasValue) cmd = define.SetRequest; - break; - case Command.ECommandDublicate.SetResponse: + break; + case ERDM_Command.SET_COMMAND_RESPONSE: + if (define.SetResponse.HasValue) cmd = define.SetResponse; - break; - } - if (cmd.Value.SingleField.HasValue) - children.Add(getChildren(cmd.Value.SingleField.Value, obj)); - if ((cmd.Value.ListOfFields?.Length ?? 0) > 0) - { - if (cmd.Value.ListOfFields.Length > 1) - throw new NotImplementedException(); + break; + } + if (!cmd.HasValue) + return result; + List children = new List(); + + switch (cmd.Value.EnumValue) + { + case Command.ECommandDublicate.GetRequest: + cmd = define.GetRequest; + break; + case Command.ECommandDublicate.GetResponse: + cmd = define.GetResponse; + break; + case Command.ECommandDublicate.SetRequest: + cmd = define.SetRequest; + break; + case Command.ECommandDublicate.SetResponse: + cmd = define.SetResponse; + break; + } + if (cmd.Value.SingleField.HasValue) + children.Add(getChildren(cmd.Value.SingleField.Value, obj)); + if ((cmd.Value.ListOfFields?.Length ?? 0) > 0) + { + if (cmd.Value.ListOfFields.Length > 1) + throw new NotImplementedException(); - children.Add(getChildren(cmd.Value.ListOfFields[0], obj)); + 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; + } + 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); + if (oneofOt != null) + return new DataTree(oneofOt.Name, 0, o); - throw new NotImplementedException(); - } - if (children.Count != 0) - return new DataTreeBranch(obj, children: children.ToArray()); - if (cmd.Value.GetIsEmpty()) - return DataTreeBranch.Empty; + throw new NotImplementedException(); } - return result; + if (children.Count != 0) + return new DataTreeBranch(obj, children: children.ToArray()); + if (cmd.Value.GetIsEmpty()) + return DataTreeBranch.Empty; } + return result; + } - public static DataTreeBranch FromObject(object obj, object key, ERDM_Command command, ERDM_Parameter parameter) - { - if (obj == null) - return DataTreeBranch.Empty; + public static DataTreeBranch FromObject(object obj, object key, ERDM_Command command, ERDM_Parameter parameter) + { + if (obj == null) + return DataTreeBranch.Empty; + + Type type = obj.GetType(); - Type type = obj.GetType(); + if (type.IsGenericType && typeof(IDictionary).IsAssignableFrom(type.GetGenericTypeDefinition())) + { + Type[] genericArguments = type.GetGenericArguments(); + Type keyType = genericArguments[0]; + Type valueType = genericArguments[1]; - if (type.IsGenericType && typeof(IDictionary).IsAssignableFrom(type.GetGenericTypeDefinition())) + var tryGetValueMethod = type.GetMethod("TryGetValue"); + object[] parameters = { key, null }; + bool found = false; + try { - Type[] genericArguments = type.GetGenericArguments(); - Type keyType = genericArguments[0]; - Type valueType = genericArguments[1]; - - var tryGetValueMethod = type.GetMethod("TryGetValue"); - object[] parameters = { key, null }; - bool found = false; - try - { - found = (bool)tryGetValueMethod.Invoke(obj, parameters); - } - catch(Exception e) - { - Logger?.LogError(e); - } + found = (bool)tryGetValueMethod.Invoke(obj, parameters); + } + catch (Exception e) + { + Logger?.LogError(e); + } - if (found) - { - // Der Wert wird im zweiten Parameter (Index 1) gespeichert - object value = parameters[1]; - obj = value; - type = value.GetType(); - } + if (found) + { + // Der Wert wird im zweiten Parameter (Index 1) gespeichert + object value = parameters[1]; + obj = value; + type = value.GetType(); } + } - bool isArray = type.IsArray; + bool isArray = type.IsArray; - if (isArray) - type = type.GetElementType(); + if (isArray) + type = type.GetElementType(); - if (type.GetCustomAttributes().FirstOrDefault(a => a.Parameter == parameter && a.Command == Tools.ConvertCommandDublicateToCommand(command) && a.IsArray == isArray) is not DataTreeObjectAttribute dataTreeObjectAttribute) - return DataTreeBranch.Unset; + if (type.GetCustomAttributes().FirstOrDefault(a => a.Parameter == parameter && a.Command == Tools.ConvertCommandDublicateToCommand(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; + 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)); + 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) { - 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))); + 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)) + if (!string.IsNullOrWhiteSpace(dataTreeObjectAttribute.Path)) + { + string[] path = dataTreeObjectAttribute.Path.Split('/'); + DataTree? route = null; + for (int i = path.Length; i != 0; i--) { - 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); + 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, children.ToArray()); + return new DataTreeBranch(obj, route.Value); + } - static DataTree[] convertToDataTree(object value, PropertyInfo[] properties, ERDM_Parameter parameter) + return new DataTreeBranch(obj, children.ToArray()); + + static DataTree[] convertToDataTree(object value, PropertyInfo[] properties, ERDM_Parameter parameter) + { + List innerChildren = new List(); + Dictionary> deeperChildren = new Dictionary>(); + foreach (var property in properties) { - List innerChildren = 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); + var attributes = property.GetCustomAttributes(); + DataTreeObjectPropertyAttribute attribute = attributes.FirstOrDefault(); + if (attributes.Count() != 1) + attribute = attributes.FirstOrDefault(a => a.Parameter == parameter); - if (attribute != null) + if (attribute != null) + { + var val = property.GetValue(value); + if (val is Enum) + val = getUnderlyingValue(val); + if (attribute.Name.Contains("/")) { - 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)) { - 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)); + ddc = new List(); + deeperChildren.TryAdd(path[0], ddc); } - else - innerChildren.Add(new DataTree(attribute.Name, attribute.Index, val)); + ddc.Add(new DataTree(path[1], attribute.Index, val)); } + else + innerChildren.Add(new DataTree(attribute.Name, attribute.Index, val)); } - foreach (var dC in deeperChildren) - { - var index = FindMissingNumbers(innerChildren.Select(ic => (int)ic.Index)).FirstOrDefault(); - innerChildren.Add(new DataTree(dC.Key, (uint)index, children: dC.Value.OrderBy(c => c.Index).ToArray())); - } - return innerChildren.OrderBy(iC => iC.Index).ToArray(); - - static IEnumerable FindMissingNumbers(IEnumerable numbers) - { - // Liste sortieren - var sortedNumbers = numbers.OrderBy(n => n).ToList(); + } + foreach (var dC in deeperChildren) + { + var index = FindMissingNumbers(innerChildren.Select(ic => (int)ic.Index)).FirstOrDefault(); + innerChildren.Add(new DataTree(dC.Key, (uint)index, children: dC.Value.OrderBy(c => c.Index).ToArray())); + } + return innerChildren.OrderBy(iC => iC.Index).ToArray(); - // Bereich (Range) bestimmen - int min = sortedNumbers.First(); - int max = sortedNumbers.Last(); + static IEnumerable FindMissingNumbers(IEnumerable numbers) + { + // Liste sortieren + var sortedNumbers = numbers.OrderBy(n => n).ToList(); - // Alle erwarteten Zahlen im Bereich erstellen - var fullRange = Enumerable.Range(min, max - min + 1); + // Bereich (Range) bestimmen + int min = sortedNumbers.First(); + int max = sortedNumbers.Last(); - // 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()); + // Alle erwarteten Zahlen im Bereich erstellen + var fullRange = Enumerable.Range(min, max - min + 1); - // Konvertierung des Enum-Werts in den zugrunde liegenden Typ - return Convert.ChangeType(enumValue, underlyingType); + // Fehlende Zahlen durch Differenz finden + return fullRange.Except(sortedNumbers); } } - - public override bool Equals(object obj) + static object getUnderlyingValue(object enumValue) { - return obj is DataTreeBranch branch && Equals(branch); + // 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 bool Equals(DataTreeBranch other) - { - if ((this.Children is null) && (other.Children is null)) - return true; + public override bool Equals(object obj) + { + return obj is DataTreeBranch branch && Equals(branch); + } - if ((this.Children is null) || (other.Children is null)) - return false; + public bool Equals(DataTreeBranch other) + { + if (this.IsUnset != other.IsUnset || this.IsEmpty != other.IsEmpty) + return false; - 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; - } + if ((this.Children is null) && (other.Children is null)) return true; - // return EqualityComparer.Default.Equals(Children, other.Children); // is not dooing its job - } - public override int GetHashCode() - { - return HashCode.Combine(Children); - } + if ((this.Children is null) || (other.Children is null)) + return false; - public static bool operator ==(DataTreeBranch left, DataTreeBranch right) + for (int i = 0; i < Children.Length; i++) { - return left.Equals(right); + 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 static bool operator !=(DataTreeBranch left, DataTreeBranch right) + 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); + } + + public override string ToString() + { + if (Children is not null) { - return !(left == right); + return "DTB:" + Environment.NewLine + String.Join(Environment.NewLine, Children.Select(c => $"{c.Name} = {c.Value}")); } + return base.ToString(); } } \ No newline at end of file diff --git a/RDMSharp/Metadata/DataTreeObjectParameterAttribute.cs b/RDMSharp/Metadata/DataTreeObjectParameterAttribute.cs index 972a01c..f056d46 100644 --- a/RDMSharp/Metadata/DataTreeObjectParameterAttribute.cs +++ b/RDMSharp/Metadata/DataTreeObjectParameterAttribute.cs @@ -19,6 +19,10 @@ public DataTreeObjectParameterAttribute(ERDM_Parameter parameter, string name) : { Parameter = parameter; } + public DataTreeObjectParameterAttribute(ERDM_Parameter parameter, string name, bool isArray) : this(parameter, name) + { + IsArray = isArray; + } public override string ToString() { return $"{Parameter} -> {Name}"; diff --git a/RDMSharp/Metadata/JSON/OneOfTypes/BytesType.cs b/RDMSharp/Metadata/JSON/OneOfTypes/BytesType.cs index be4253d..4422995 100644 --- a/RDMSharp/Metadata/JSON/OneOfTypes/BytesType.cs +++ b/RDMSharp/Metadata/JSON/OneOfTypes/BytesType.cs @@ -191,7 +191,17 @@ byte[] parseData(string format, object value) //Fallback default: if (value is string str) - return Encoding.UTF8.GetBytes(str); + return Encoding.ASCII.GetBytes(str); + if (value is IReadOnlyCollection strings) + { + List bytes = new List(); + foreach (string _str in strings) + { + bytes.AddRange(Encoding.ASCII.GetBytes(_str)); + bytes.Add(0x00); + } + return bytes.ToArray(); + } if (value is byte[] byteArray) return byteArray; throw new NotImplementedException($"There is no implementation for {nameof(Format)}: {Format} and Value: {value}"); diff --git a/RDMSharp/Metadata/MetadataFactory.cs b/RDMSharp/Metadata/MetadataFactory.cs index 85efa83..59cebc6 100644 --- a/RDMSharp/Metadata/MetadataFactory.cs +++ b/RDMSharp/Metadata/MetadataFactory.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; @@ -15,458 +14,457 @@ [assembly: InternalsVisibleTo("RDMSharpTests")] -namespace RDMSharp.Metadata +namespace RDMSharp.Metadata; + +public static class MetadataFactory { - public static class MetadataFactory + private static readonly ILogger Logger = Logging.CreateLogger(typeof(MetadataFactory)); + private const string SCHEMA_FILE_NAME = "schema.json"; + private const string JSON_ENDING = ".json"; + private static ConcurrentDictionary metadataVersionList; + private static ConcurrentDictionary> metadataVersionDefinesBagDictionary; + private static ConcurrentDictionary parameterBagDefineCache; + private static List resourceProvider = new List() { typeof(MetadataFactory).Assembly }; + + public static void AddResourceProvider(Assembly assembly) { - private static readonly ILogger Logger = Logging.CreateLogger(typeof(MetadataFactory)); - private const string SCHEMA_FILE_NAME = "schema.json"; - private const string JSON_ENDING = ".json"; - private static ConcurrentDictionary metadataVersionList; - private static ConcurrentDictionary> metadataVersionDefinesBagDictionary; - private static ConcurrentDictionary parameterBagDefineCache; - private static List resourceProvider = new List() { typeof(MetadataFactory).Assembly }; - - public static void AddResourceProvider(Assembly assembly) - { - resourceProvider.Add(assembly); - } - public static IReadOnlyDictionary MetadataVersionList + resourceProvider.Add(assembly); + } + public static IReadOnlyDictionary MetadataVersionList + { + get { - get + if (metadataVersionList == null) { - if (metadataVersionList == null) + metadataVersionList = new ConcurrentDictionary(); + foreach (Assembly assembly in resourceProvider) { - metadataVersionList = new ConcurrentDictionary(); - foreach (Assembly assembly in resourceProvider) + try { - try - { - var resoures = GetResources(assembly); - var metaDataVersions = resoures.Select(r => new MetadataVersion(r, assembly)); - foreach (var mv in metaDataVersions) - metadataVersionList.TryAdd(mv.Path, mv); - } - catch (Exception e) - { - Logger?.LogError(e); - } + var resoures = GetResources(assembly); + var metaDataVersions = resoures.Select(r => new MetadataVersion(r, assembly)); + foreach (var mv in metaDataVersions) + metadataVersionList.TryAdd(mv.Path, mv); + } + catch (Exception e) + { + Logger?.LogError(e); } } - return metadataVersionList.AsReadOnly(); } + return metadataVersionList.AsReadOnly(); } - public static IReadOnlyCollection GetResources(Assembly assembly) - { - return assembly.GetManifestResourceNames().Where(p => p.EndsWith(JSON_ENDING)).ToList().AsReadOnly(); - } - private static void fillDefaultMetadataVersionList() - { - if (metadataVersionDefinesBagDictionary != null) - return; + } + public static IReadOnlyCollection GetResources(Assembly assembly) + { + return assembly.GetManifestResourceNames().Where(p => p.EndsWith(JSON_ENDING)).ToList().AsReadOnly(); + } + private static void fillDefaultMetadataVersionList() + { + if (metadataVersionDefinesBagDictionary != null) + return; - metadataVersionDefinesBagDictionary = new ConcurrentDictionary>(); - foreach (Assembly assembly in resourceProvider) + metadataVersionDefinesBagDictionary = new ConcurrentDictionary>(); + foreach (Assembly assembly in resourceProvider) + { + try { - try - { - var metaDataVersions = GetResources(assembly).Select(r => new MetadataVersion(r, assembly)); - foreach (var mv in metaDataVersions) - metadataVersionList.TryAdd(mv.Path, mv); - } - catch (Exception e) - { - Logger?.LogError(e); - } + var metaDataVersions = GetResources(assembly).Select(r => new MetadataVersion(r, assembly)); + foreach (var mv in metaDataVersions) + metadataVersionList.TryAdd(mv.Path, mv); } + catch (Exception e) + { + Logger?.LogError(e); + } + } - var schemaList = GetMetadataSchemaVersions(); - ConcurrentDictionary versionSchemas = new ConcurrentDictionary(); + var schemaList = GetMetadataSchemaVersions(); + ConcurrentDictionary versionSchemas = new ConcurrentDictionary(); - var nonSchemaVersions = metadataVersionList.Values.Where(_mv => !_mv.IsSchema).ToList(); + var nonSchemaVersions = metadataVersionList.Values.Where(_mv => !_mv.IsSchema).ToList(); - ParallelOptions parallelOptions = new ParallelOptions - { - MaxDegreeOfParallelism = Environment.ProcessorCount, // Optional: Set the maximum degree of parallelism - }; - Parallel.ForEach(nonSchemaVersions, parallelOptions, mv => + ParallelOptions parallelOptions = new ParallelOptions + { + MaxDegreeOfParallelism = Environment.ProcessorCount, // Optional: Set the maximum degree of parallelism + }; + Parallel.ForEach(nonSchemaVersions, parallelOptions, mv => + { + try { - try + var schema = schemaList.First(s => s.Version.Equals(mv.Version)); + if (!versionSchemas.TryGetValue(schema.Version, out JsonSchema jsonSchema)) { - 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); - metadataVersionDefinesBagDictionary.AddOrUpdate(schema, - _ => new List { jsonDefine }, - (_, list) => - { - lock (list) - { - list.Add(jsonDefine); - return list; - } - }); - } - else - throw new Exception($"Schema Invalid for {mv.Name}"); + jsonSchema = JsonSchema.FromText(new MetadataBag(schema).Content); + versionSchemas.TryAdd(schema.Version, jsonSchema); } - catch (Exception e) + MetadataBag metadataBag = new MetadataBag(mv); + var result = jsonSchema.Evaluate(JsonNode.Parse(metadataBag.Content)); + if (result.IsValid) { - Logger?.LogError($"Exception while Deserialize {mv.Name}", e); + MetadataJSONObjectDefine jsonDefine = JsonSerializer.Deserialize(metadataBag.Content); + metadataVersionDefinesBagDictionary.AddOrUpdate(schema, + _ => new List { jsonDefine }, + (_, list) => + { + lock (list) + { + list.Add(jsonDefine); + return list; + } + }); } - }); - } + else + throw new Exception($"Schema Invalid for {mv.Name}"); + } + catch (Exception e) + { + Logger?.LogError($"Exception while Deserialize {mv.Name}", e); + } + }); + } - public static IReadOnlyCollection GetMetadataSchemaVersions() + public static IReadOnlyCollection GetMetadataSchemaVersions() + { + return MetadataVersionList.Values.Where(r => r.IsSchema).ToList().AsReadOnly(); + } + public static IReadOnlyCollection GetMetadataDefineVersions() + { + try { - return MetadataVersionList.Values.Where(r => r.IsSchema).ToList().AsReadOnly(); + return MetadataVersionList.Values.Where(r => !r.IsSchema).ToList().AsReadOnly(); } - public static IReadOnlyCollection GetMetadataDefineVersions() + finally { - try - { - return MetadataVersionList.Values.Where(r => !r.IsSchema).ToList().AsReadOnly(); - } - finally + fillDefaultMetadataVersionList(); + } + } + public 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) { - fillDefaultMetadataVersionList(); + parameterBagDefineCache.TryAdd(parameter, define); + return define; } } - public static MetadataJSONObjectDefine GetDefine(ParameterBag parameter) + catch (Exception ex) { - try - { - if (parameterBagDefineCache == null) - parameterBagDefineCache = new ConcurrentDictionary(); - - if (parameterBagDefineCache.TryGetValue(parameter, out var define)) - return define; + Logger?.LogError(ex); + } + if ((ushort)parameter.PID < 0x8000 || (ushort)parameter.PID > 0xFFDF) + throw new DefineNotFoundException($"{parameter}"); - define = getDefine(parameter); - if (define != null) - { - parameterBagDefineCache.TryAdd(parameter, define); - return define; - } + return null; + } + public static void AddDefineFromParameterDescription(UID uid, SubDevice subDevice, RDMDeviceInfo deviceInfo, RDMParameterDescription parameterDescription) + { + SubdevicesForRequests[] getRequestSubdeviceRange = null; + SubdevicesForResponses[] getResponseSubdeviceRange = null; + SubdevicesForRequests[] setRequestSubdeviceRange = null; + SubdevicesForResponses[] setResponseSubdeviceRange = null; + Command? getCommandRequest = null; + Command? getCommandResponse = null; + Command? setCommandRequest = null; + Command? setCommandResponse = null; + if (deviceInfo.SubDeviceCount == 0) + { + if (parameterDescription.CommandClass.HasFlag(ERDM_CommandClass.GET)) + { + getRequestSubdeviceRange = new SubdevicesForRequests[] { new SubdevicesForRequests(SubdevicesForRequests.ESubdevicesForRequests.Root) }; + getResponseSubdeviceRange = new SubdevicesForResponses[] { new SubdevicesForResponses(SubdevicesForResponses.ESubdevicesForResponses.Root) }; } - catch (Exception ex) + if (parameterDescription.CommandClass.HasFlag(ERDM_CommandClass.SET)) { - Logger?.LogError(ex); + setRequestSubdeviceRange = new SubdevicesForRequests[] { new SubdevicesForRequests(SubdevicesForRequests.ESubdevicesForRequests.Root) }; + setResponseSubdeviceRange = new SubdevicesForResponses[] { new SubdevicesForResponses(SubdevicesForResponses.ESubdevicesForResponses.Root) }; } - if ((ushort)parameter.PID < 0x8000 || (ushort)parameter.PID > 0xFFDF) - throw new DefineNotFoundException($"{parameter}"); + } - return null; + string name = parameterDescription.Description; + string displayName = getDisplayName(parameterDescription); + + if (parameterDescription.CommandClass == ERDM_CommandClass.SET) + { + setCommandRequest = new Command(); + setCommandResponse = new Command(); } - public static void AddDefineFromParameterDescription(UID uid,SubDevice subDevice, RDMDeviceInfo deviceInfo, RDMParameterDescription parameterDescription) + else { - SubdevicesForRequests[] getRequestSubdeviceRange = null; - SubdevicesForResponses[] getResponseSubdeviceRange = null; - SubdevicesForRequests[] setRequestSubdeviceRange = null; - SubdevicesForResponses[] setResponseSubdeviceRange = null; - Command? getCommandRequest = null; - Command? getCommandResponse = null; - Command? setCommandRequest = null; - Command? setCommandResponse = null; - if (deviceInfo.SubDeviceCount == 0) + if (parameterDescription.CommandClass.HasFlag(ERDM_CommandClass.GET)) { - if (parameterDescription.CommandClass.HasFlag(ERDM_CommandClass.GET)) + getCommandRequest = new Command(); + OneOfTypes? oneOfType = null; + LabeledIntegerType[] labeledIntegerTypes = getLabeledIntegerTypes(parameterDescription); + switch (parameterDescription.DataType) { - getRequestSubdeviceRange = new SubdevicesForRequests[] { new SubdevicesForRequests(SubdevicesForRequests.ESubdevicesForRequests.Root) }; - getResponseSubdeviceRange = new SubdevicesForResponses[] { new SubdevicesForResponses(SubdevicesForResponses.ESubdevicesForResponses.Root) }; - } - if (parameterDescription.CommandClass.HasFlag(ERDM_CommandClass.SET)) - { - setRequestSubdeviceRange = new SubdevicesForRequests[] { new SubdevicesForRequests(SubdevicesForRequests.ESubdevicesForRequests.Root) }; - setResponseSubdeviceRange = new SubdevicesForResponses[] { new SubdevicesForResponses(SubdevicesForResponses.ESubdevicesForResponses.Root) }; + case ERDM_DataType.STRING: + oneOfType = new OneOfTypes(new StringType(name, displayName, null, null, "string", null, null, 0, parameterDescription.PDLSize, null, null, true)); + break; + case ERDM_DataType.UINT8: + oneOfType = new OneOfTypes(new IntegerType(name, displayName, null, null, EIntegerType.UInt8, labeledIntegerTypes, labeledIntegerTypes != null, new Range[] { new Range((byte)parameterDescription.MinValidValue, (byte)parameterDescription.MaxValidValue) }, parameterDescription.Unit, (int)Tools.GetNormalizedValue(parameterDescription.Prefix, 1), 1)); + break; + case ERDM_DataType.INT8: + oneOfType = new OneOfTypes(new IntegerType(name, displayName, null, null, EIntegerType.Int8, labeledIntegerTypes, labeledIntegerTypes != null, new Range[] { new Range((sbyte)parameterDescription.MinValidValue, (sbyte)parameterDescription.MaxValidValue) }, parameterDescription.Unit, (int)Tools.GetNormalizedValue(parameterDescription.Prefix, 1), 1)); + break; + + case ERDM_DataType.UINT16: + oneOfType = new OneOfTypes(new IntegerType(name, displayName, null, null, EIntegerType.UInt16, labeledIntegerTypes, labeledIntegerTypes != null, new Range[] { new Range((ushort)parameterDescription.MinValidValue, (ushort)parameterDescription.MaxValidValue) }, parameterDescription.Unit, (int)Tools.GetNormalizedValue(parameterDescription.Prefix, 1), 1)); + break; + case ERDM_DataType.INT16: + oneOfType = new OneOfTypes(new IntegerType(name, displayName, null, null, EIntegerType.Int16, labeledIntegerTypes, labeledIntegerTypes != null, new Range[] { new Range((short)parameterDescription.MinValidValue, (short)parameterDescription.MaxValidValue) }, parameterDescription.Unit, (int)Tools.GetNormalizedValue(parameterDescription.Prefix, 1), 1)); + break; + default: + break; } + if (oneOfType.HasValue) + getCommandResponse = new Command(oneOfType.Value); + else + getCommandResponse = new Command(); } - - string name = parameterDescription.Description; - string displayName = getDisplayName(parameterDescription); - - if (parameterDescription.CommandClass == ERDM_CommandClass.SET) + if (parameterDescription.CommandClass.HasFlag(ERDM_CommandClass.SET)) { - setCommandRequest = new Command(); + setCommandRequest = new Command(Command.ECommandDublicate.GetResponse); setCommandResponse = new Command(); } - else - { - if (parameterDescription.CommandClass.HasFlag(ERDM_CommandClass.GET)) - { - getCommandRequest = new Command(); - OneOfTypes? oneOfType = null; - LabeledIntegerType[] labeledIntegerTypes = getLabeledIntegerTypes(parameterDescription); - switch (parameterDescription.DataType) - { - case ERDM_DataType.STRING: - oneOfType = new OneOfTypes(new StringType(name, displayName, null, null, "string", null, null, 0, parameterDescription.PDLSize, null, null, true)); - break; - case ERDM_DataType.UINT8: - oneOfType = new OneOfTypes(new IntegerType(name, displayName, null, null, EIntegerType.UInt8, labeledIntegerTypes, labeledIntegerTypes != null, new Range[] { new Range((byte)parameterDescription.MinValidValue, (byte)parameterDescription.MaxValidValue) }, parameterDescription.Unit, (int)Tools.GetNormalizedValue(parameterDescription.Prefix, 1), 1)); - break; - case ERDM_DataType.INT8: - oneOfType = new OneOfTypes(new IntegerType(name, displayName, null, null, EIntegerType.Int8, labeledIntegerTypes, labeledIntegerTypes != null, new Range[] { new Range((sbyte)parameterDescription.MinValidValue, (sbyte)parameterDescription.MaxValidValue) }, parameterDescription.Unit, (int)Tools.GetNormalizedValue(parameterDescription.Prefix, 1), 1)); - break; - - case ERDM_DataType.UINT16: - oneOfType = new OneOfTypes(new IntegerType(name, displayName, null, null, EIntegerType.UInt16, labeledIntegerTypes, labeledIntegerTypes != null, new Range[] { new Range((ushort)parameterDescription.MinValidValue, (ushort)parameterDescription.MaxValidValue) }, parameterDescription.Unit, (int)Tools.GetNormalizedValue(parameterDescription.Prefix, 1), 1)); - break; - case ERDM_DataType.INT16: - oneOfType = new OneOfTypes(new IntegerType(name, displayName, null, null, EIntegerType.Int16, labeledIntegerTypes, labeledIntegerTypes != null, new Range[] { new Range((short)parameterDescription.MinValidValue, (short)parameterDescription.MaxValidValue) }, parameterDescription.Unit, (int)Tools.GetNormalizedValue(parameterDescription.Prefix, 1), 1)); - break; - default: - break; - } - if (oneOfType.HasValue) - getCommandResponse = new Command(oneOfType.Value); - else - getCommandResponse = new Command(); - } - if (parameterDescription.CommandClass.HasFlag(ERDM_CommandClass.SET)) - { - setCommandRequest = new Command(Command.ECommandDublicate.GetResponse); - setCommandResponse = new Command(); - } - } - MetadataJSONObjectDefine define = new MetadataJSONObjectDefine( - parameterDescription.Description, - displayName, - null, - uid.ManufacturerID, - deviceInfo.DeviceModelId, - deviceInfo.SoftwareVersionId, - parameterDescription.ParameterId, - 0, - getRequestSubdeviceRange, - getResponseSubdeviceRange, - setRequestSubdeviceRange, - setResponseSubdeviceRange, - getCommandRequest, - getCommandResponse, - setCommandRequest, - setCommandResponse); - - parameterBagDefineCache.TryAdd(new ParameterBag((ERDM_Parameter)define.PID, define.ManufacturerID, define.DeviceModelID, define.SoftwareVersionID), define); } - private static string getDisplayName(RDMParameterDescription parameterDescription) + MetadataJSONObjectDefine define = new MetadataJSONObjectDefine( + parameterDescription.Description, + displayName, + null, + uid.ManufacturerID, + deviceInfo.DeviceModelId, + deviceInfo.SoftwareVersionId, + parameterDescription.ParameterId, + 0, + getRequestSubdeviceRange, + getResponseSubdeviceRange, + setRequestSubdeviceRange, + setResponseSubdeviceRange, + getCommandRequest, + getCommandResponse, + setCommandRequest, + setCommandResponse); + + parameterBagDefineCache.TryAdd(new ParameterBag((ERDM_Parameter)define.PID, define.ManufacturerID, define.DeviceModelID, define.SoftwareVersionID), define); + } + private static string getDisplayName(RDMParameterDescription parameterDescription) + { + if (parameterDescription.Description.Contains(' ') && parameterDescription.Description.Contains('=')) { - if(parameterDescription.Description.Contains(' ') && parameterDescription.Description.Contains('=')) - { - string[] parts = parameterDescription.Description.Split(' '); - string result = string.Join(' ', parts.TakeWhile(p => !p.Contains('='))); - return result; - } - return null; + string[] parts = parameterDescription.Description.Split(' '); + string result = string.Join(' ', parts.TakeWhile(p => !p.Contains('='))); + return result; } - private static LabeledIntegerType[] getLabeledIntegerTypes(RDMParameterDescription parameterDescription) + return null; + } + private static LabeledIntegerType[] getLabeledIntegerTypes(RDMParameterDescription parameterDescription) + { + List labeledIntegerTypes = new List(); + if (parameterDescription.Description.Contains(' ') && parameterDescription.Description.Contains('=')) { - List labeledIntegerTypes = new List(); - if (parameterDescription.Description.Contains(' ') && parameterDescription.Description.Contains('=')) + var parts = parameterDescription.Description.Split(' ').Where(p => p.Contains('=')); + foreach (var part in parts) { - var parts = parameterDescription.Description.Split(' ').Where(p => p.Contains('=')); - foreach (var part in parts) + string[] labelAndValue = part.Split('='); + int value = 0; + if (labelAndValue.Length == 2) { - string[] labelAndValue = part.Split('='); - int value = 0; - if (labelAndValue.Length == 2) - { - if (int.TryParse(labelAndValue[0], out value)) - labeledIntegerTypes.Add(new LabeledIntegerType(labelAndValue[1], value)); - else if (int.TryParse(labelAndValue[1], out value)) - labeledIntegerTypes.Add(new LabeledIntegerType(labelAndValue[0], value)); - } + if (int.TryParse(labelAndValue[0], out value)) + labeledIntegerTypes.Add(new LabeledIntegerType(labelAndValue[1], value)); + else if (int.TryParse(labelAndValue[1], out value)) + labeledIntegerTypes.Add(new LabeledIntegerType(labelAndValue[0], value)); } } - if (labeledIntegerTypes.Count == 0) - return null; - return labeledIntegerTypes.ToArray(); } - private static MetadataJSONObjectDefine getDefine(ParameterBag parameter) - { - var version = GetMetadataSchemaVersions().First(); - if (parameter.PID == ERDM_Parameter.QUEUED_MESSAGE) - return metadataVersionDefinesBagDictionary[version].FirstOrDefault(d => d.PID == (ushort)parameter.PID); + if (labeledIntegerTypes.Count == 0) + return null; + return labeledIntegerTypes.ToArray(); + } + private static MetadataJSONObjectDefine getDefine(ParameterBag parameter) + { + var version = GetMetadataSchemaVersions().First(); + if (parameter.PID == ERDM_Parameter.QUEUED_MESSAGE && metadataVersionDefinesBagDictionary is not null) + return metadataVersionDefinesBagDictionary[version].FirstOrDefault(d => d.PID == (ushort)parameter.PID); - fillDefaultMetadataVersionList(); - var possibleDefines = metadataVersionDefinesBagDictionary[version].FindAll(d => d.PID == (ushort)parameter.PID && d.ManufacturerID == parameter.ManufacturerID); - if (possibleDefines.Count == 1) - return possibleDefines[0]; + 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) + if (possibleDefines.Count > 1) + { + MetadataJSONObjectDefine define = possibleDefines.FirstOrDefault(d => d.DeviceModelID == null && d.SoftwareVersionID == null); + if (parameter.DeviceModelID != null) { - 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 == 0) + return define; + if (possibleDefines.Count == 1) + define = possibleDefines[0]; + else if (possibleDefines.Count > 1) { - possibleDefines = possibleDefines.Where(d => d.DeviceModelID == parameter.DeviceModelID).ToList(); - if (possibleDefines.Count == 0) - return define; - 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 == null) ?? define; - if (parameter.SoftwareVersionID != null) - { - define = possibleDefines.FirstOrDefault(d => d.SoftwareVersionID == parameter.SoftwareVersionID) ?? define; + define = possibleDefines.FirstOrDefault(d => d.SoftwareVersionID == parameter.SoftwareVersionID) ?? define; - if (define == null) - define = possibleDefines.MinBy(d => parameter.SoftwareVersionID - d.SoftwareVersionID); - } + 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"); + return possibleDefines.MaxBy(d => d.Version); + } + if (parameter.ManufacturerID == 0) + throw new InvalidOperationException($"{parameter.ManufacturerID} of 0 should lead to exact 1 Define"); - if ((ushort)parameter.PID < 0x8000 || (ushort)parameter.PID > 0xFFDF) - throw new DefineNotFoundException($"{parameter}"); - return null; + if ((ushort)parameter.PID < 0x8000 || (ushort)parameter.PID > 0xFFDF) + throw new DefineNotFoundException($"{parameter}"); + return null; + } + + internal static IEnumerable ParsePayloadToData(MetadataJSONObjectDefine define, Command.ECommandDublicate commandType, DataTreeBranch payload) + { + define.GetCommand(commandType, out Command? _command); + if (_command is not Command command) + throw new InvalidOperationException(); + List result = new List(); + if (command.GetIsEmpty()) + { + result.Add(new byte[0]); + return result.AsReadOnly(); } - internal static IEnumerable ParsePayloadToData(MetadataJSONObjectDefine define, Command.ECommandDublicate commandType, DataTreeBranch payload) + if (command.SingleField.HasValue && payload.Children.SingleOrDefault() is DataTree dataTree) { - define.GetCommand(commandType, out Command? _command); - if (_command is not Command command) - throw new InvalidOperationException(); - List result = new List(); - if (command.GetIsEmpty()) - { - result.Add(new byte[0]); - return result.AsReadOnly(); - } + result.AddRange(command.SingleField.Value.ParsePayloadToData(dataTree)); + return result.AsReadOnly(); + } + if (command.ListOfFields.Length != 0 && payload.Children is DataTree[] dataTreeArray) + { + if (dataTreeArray.Length != command.ListOfFields.Length) + throw new IndexOutOfRangeException(); - if (command.SingleField.HasValue && payload.Children.SingleOrDefault() is DataTree dataTree) + List data = new List(); + for (int i = 0; i < command.ListOfFields.Length; i++) { - result.AddRange(command.SingleField.Value.ParsePayloadToData(dataTree)); - return result.AsReadOnly(); - } - 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++) + var newData = command.ListOfFields[i].ParsePayloadToData(dataTreeArray[i]); + foreach (var nData in newData) { - var newData = command.ListOfFields[i].ParsePayloadToData(dataTreeArray[i]); - foreach(var nData in newData) + if (data.Count + nData.Length > 231) { - if (data.Count + nData.Length > 231) - { - result.Add(data.ToArray()); - data.Clear(); - } - data.AddRange(nData); + result.Add(data.ToArray()); + data.Clear(); } - //data.AddRange(newData.SelectMany(en=>en).ToArray()); + data.AddRange(nData); } - - if (data.Count != 0) - result.Add(data.ToArray()); - return result.AsReadOnly(); + //data.AddRange(newData.SelectMany(en=>en).ToArray()); } - throw new ArithmeticException(); + if (data.Count != 0) + result.Add(data.ToArray()); + return result.AsReadOnly(); } - internal static DataTreeBranch ParseDataToPayload(MetadataJSONObjectDefine define, Command.ECommandDublicate 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) - { - Logger?.LogError(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 IEnumerable GetRequestMessageData(ParameterBag parameter, DataTreeBranch payloadData) - { - return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicate.GetRequest, payloadData); - } - internal static IEnumerable GetResponseMessageData(ParameterBag parameter, DataTreeBranch payloadData) + throw new ArithmeticException(); + } + internal static DataTreeBranch ParseDataToPayload(MetadataJSONObjectDefine define, Command.ECommandDublicate commandType, byte[] data) + { + define.GetCommand(commandType, out Command? _command); + if (_command is not Command command) + throw new InvalidOperationException(); + try { - return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicate.GetResponse, payloadData); + if (command.GetIsEmpty()) + return DataTreeBranch.Empty; } - internal static IEnumerable SetRequestMessageData(ParameterBag parameter, DataTreeBranch payloadData) + catch (Exception e) { - return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicate.SetRequest, payloadData); + Logger?.LogError(e); } - internal static IEnumerable SetResponseMessageData(ParameterBag parameter, DataTreeBranch payloadData) + + if (command.SingleField.HasValue) + return new DataTreeBranch(define, commandType, command.SingleField.Value.ParseDataToPayload(ref data)); + + if (command.ListOfFields.Length != 0) { - return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicate.SetResponse, payloadData); + 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()); } - private static List definedDataTreeObjects; - public static IReadOnlyCollection DefinedDataTreeObjects + throw new ArithmeticException(); + } + internal static IEnumerable GetRequestMessageData(ParameterBag parameter, DataTreeBranch payloadData) + { + return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicate.GetRequest, payloadData); + } + internal static IEnumerable GetResponseMessageData(ParameterBag parameter, DataTreeBranch payloadData) + { + return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicate.GetResponse, payloadData); + } + internal static IEnumerable SetRequestMessageData(ParameterBag parameter, DataTreeBranch payloadData) + { + return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicate.SetRequest, payloadData); + } + internal static IEnumerable SetResponseMessageData(ParameterBag parameter, DataTreeBranch payloadData) + { + return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicate.SetResponse, payloadData); + } + + private static List definedDataTreeObjects; + public static IReadOnlyCollection DefinedDataTreeObjects + { + get { - get - { - fillDefinedDataTreeObjects(); - return definedDataTreeObjects; - } + fillDefinedDataTreeObjects(); + return definedDataTreeObjects; } + } - private static void fillDefinedDataTreeObjects() - { - if (definedDataTreeObjects != null) - return; + private static void fillDefinedDataTreeObjects() + { + if (definedDataTreeObjects != null) + return; - definedDataTreeObjects = new List(); + definedDataTreeObjects = new List(); - definedDataTreeObjects.AddRange(Tools.FindClassesWithAttribute()); - } + definedDataTreeObjects.AddRange(Tools.FindClassesWithAttribute()); + } - public static Type GetDefinedDataTreeObjectType(MetadataJSONObjectDefine define, Command.ECommandDublicate commandType) - { - return GetDefinedDataTreeObjectType((ERDM_Parameter)define.PID, commandType); - } - public static Type GetDefinedDataTreeObjectType(MetadataJSONObjectDefine define, ERDM_Command command) - { - Command.ECommandDublicate commandType = Tools.ConvertCommandDublicateToCommand(command); - return GetDefinedDataTreeObjectType((ERDM_Parameter)define.PID, commandType); - } - public static Type GetDefinedDataTreeObjectType(ERDM_Parameter parameter, ERDM_Command command) - { - Command.ECommandDublicate commandType = Tools.ConvertCommandDublicateToCommand(command); - return GetDefinedDataTreeObjectType(parameter, commandType); - } - public static Type GetDefinedDataTreeObjectType(ERDM_Parameter parameter, Command.ECommandDublicate commandType) + public static Type GetDefinedDataTreeObjectType(MetadataJSONObjectDefine define, Command.ECommandDublicate commandType) + { + return GetDefinedDataTreeObjectType((ERDM_Parameter)define.PID, commandType); + } + public static Type GetDefinedDataTreeObjectType(MetadataJSONObjectDefine define, ERDM_Command command) + { + Command.ECommandDublicate commandType = Tools.ConvertCommandDublicateToCommand(command); + return GetDefinedDataTreeObjectType((ERDM_Parameter)define.PID, commandType); + } + public static Type GetDefinedDataTreeObjectType(ERDM_Parameter parameter, ERDM_Command command) + { + Command.ECommandDublicate commandType = Tools.ConvertCommandDublicateToCommand(command); + return GetDefinedDataTreeObjectType(parameter, commandType); + } + public static Type GetDefinedDataTreeObjectType(ERDM_Parameter parameter, Command.ECommandDublicate commandType) + { + return DefinedDataTreeObjects.Where(t => { - return DefinedDataTreeObjects.Where(t => - { - if (t.GetCustomAttributes().Any(attribute => attribute.Parameter == parameter && attribute.Command == commandType)) - return true; - return false; - }).FirstOrDefault(); - } + if (t.GetCustomAttributes().Any(attribute => attribute.Parameter == parameter && attribute.Command == commandType)) + return true; + return false; + }).FirstOrDefault(); } } diff --git a/RDMSharp/RDM/AsyncRDMRequestHelper.cs b/RDMSharp/RDM/AsyncRDMRequestHelper.cs index b73e745..1fb4570 100644 --- a/RDMSharp/RDM/AsyncRDMRequestHelper.cs +++ b/RDMSharp/RDM/AsyncRDMRequestHelper.cs @@ -1,244 +1,240 @@ using Microsoft.Extensions.Logging; using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace RDMSharp -{ - public class AsyncRDMRequestHelper : IDisposable +namespace RDMSharp; + +public class AsyncRDMRequestHelper : IDisposable +{ + private static readonly ILogger Logger = Logging.CreateLogger(); + private static readonly Random random = new Random(); + private readonly ConcurrentDictionary buffer = new ConcurrentDictionary(); + private readonly Func _sendMethode; + private CancellationTokenSource _cts; + public bool IsDisposing, IsDisposed; + public AsyncRDMRequestHelper(Func sendMethode) { - private static readonly ILogger Logger = Logging.CreateLogger(); - private static readonly Random random = new Random(); - private readonly ConcurrentDictionary buffer = new ConcurrentDictionary(); - private readonly Func _sendMethode; - private CancellationTokenSource _cts; - public bool IsDisposing, IsDisposed; - public AsyncRDMRequestHelper(Func sendMethode) - { - _cts = new CancellationTokenSource(); - _sendMethode = sendMethode; - } + _cts = new CancellationTokenSource(); + _sendMethode = sendMethode; + } - public void Dispose() - { - if (this.IsDisposing || this.IsDisposed) - return; - this.IsDisposing = true; - _cts.Cancel(); - buffer.Clear(); - _cts.Dispose(); - this.IsDisposed = true; - this.IsDisposing = false; - } + public void Dispose() + { + if (this.IsDisposing || this.IsDisposed) + return; + this.IsDisposing = true; + _cts.Cancel(); + buffer.Clear(); + _cts.Dispose(); + this.IsDisposed = true; + this.IsDisposing = false; + } - public bool ReceiveMessage(RDMMessage rdmMessage) + public bool ReceiveMessage(RDMMessage rdmMessage) + { + if (this.IsDisposing || this.IsDisposed) + return false; + + if (rdmMessage.Command == ERDM_Command.DISCOVERY_COMMAND_RESPONSE) { - if (this.IsDisposing || this.IsDisposed) + var o = buffer.FirstOrDefault(b => b.Value.Request.Parameter == rdmMessage.Parameter); + if (o.Value == null) return false; - if (rdmMessage.Command == ERDM_Command.DISCOVERY_COMMAND_RESPONSE) + updateBag(o.Value, rdmMessage); + return true; + } + //By Key + var key = generateKey(rdmMessage); + if (buffer.TryGetValue(key, out AsyncBufferBag bag)) + if (checkNonQueued(bag.Request, rdmMessage)) { - var o = buffer.FirstOrDefault(b => b.Value.Request.Parameter == rdmMessage.Parameter); - if (o.Value == null) - return false; - - updateBag(o.Value, rdmMessage); + updateBag(bag, rdmMessage); return true; } - //By Key - var key = generateKey(rdmMessage); - if (buffer.TryGetValue(key, out AsyncBufferBag bag)) - if (checkNonQueued(bag.Request, rdmMessage)) - { - updateBag(bag, rdmMessage); - return true; - } - //None Queued Parameters - var obj = buffer.Where(b => b.Value.Request.Parameter != ERDM_Parameter.QUEUED_MESSAGE).FirstOrDefault(b => b.Value.Response == null && checkNonQueued(b.Value.Request, rdmMessage)); - if (obj.Value != null) - { - updateBag(obj.Value, rdmMessage); - return true; - } - //Queued Parameters - obj = buffer.Where(b => b.Value.Request.Parameter == ERDM_Parameter.QUEUED_MESSAGE).FirstOrDefault(b => b.Value.Response == null && checkQueued(b.Value.Request, rdmMessage)); - if (obj.Value != null) - { - updateBag(obj.Value, rdmMessage); - return true; - } + //None Queued Parameters + var obj = buffer.Where(b => b.Value.Request.Parameter != ERDM_Parameter.QUEUED_MESSAGE).FirstOrDefault(b => b.Value.Response == null && checkNonQueued(b.Value.Request, rdmMessage)); + if (obj.Value != null) + { + updateBag(obj.Value, rdmMessage); + return true; + } + //Queued Parameters + obj = buffer.Where(b => b.Value.Request.Parameter == ERDM_Parameter.QUEUED_MESSAGE).FirstOrDefault(b => b.Value.Response == null && checkQueued(b.Value.Request, rdmMessage)); + if (obj.Value != null) + { + updateBag(obj.Value, rdmMessage); + return true; + } - void updateBag(AsyncBufferBag bag, RDMMessage response) - { - bag.SetResponse(response); - buffer.AddOrUpdate(bag.Key, bag, (key, oldValue) => bag); - } - return false; + void updateBag(AsyncBufferBag bag, RDMMessage response) + { + bag.SetResponse(response); + buffer.AddOrUpdate(bag.Key, bag, (key, oldValue) => bag); + } + return false; - bool checkNonQueued(RDMMessage request, RDMMessage response) - { - if (request.Parameter != response.Parameter) - return false; - if (request.TransactionCounter != response.TransactionCounter) - return false; - if (request.SubDevice != response.SubDevice) - return false; - if (request.SourceUID != response.DestUID) - return false; - if (request.DestUID != response.SourceUID) - return false; - if ((request.Command | ERDM_Command.RESPONSE) != response.Command) - return false; + bool checkNonQueued(RDMMessage request, RDMMessage response) + { + if (request.Parameter != response.Parameter) + return false; + if (request.TransactionCounter != response.TransactionCounter) + return false; + if (request.SubDevice != response.SubDevice) + return false; + if (request.SourceUID != response.DestUID) + return false; + if (request.DestUID != response.SourceUID) + return false; + if ((request.Command | ERDM_Command.RESPONSE) != response.Command) + return false; - return true; - } - bool checkQueued(RDMMessage request, RDMMessage response) - { - if (request.TransactionCounter != response.TransactionCounter) - return false; - if (request.SubDevice != response.SubDevice) - return false; - if (request.SourceUID != response.DestUID) - return false; - if (request.DestUID != response.SourceUID) - return false; - if ((request.Command | ERDM_Command.RESPONSE) != response.Command) - return false; + return true; + } + bool checkQueued(RDMMessage request, RDMMessage response) + { + if (request.TransactionCounter != response.TransactionCounter) + return false; + if (request.SubDevice != response.SubDevice) + return false; + if (request.SourceUID != response.DestUID) + return false; + if (request.DestUID != response.SourceUID) + return false; - return true; - } + return true; } + } - public async Task RequestMessage(RDMMessage request, bool setTransactionCounter=true) + public async Task RequestMessage(RDMMessage request, bool setTransactionCounter = true) + { + try { - try + if (setTransactionCounter) + request.TransactionCounter = RDMSharp.Instance.getTransactionCounter(request.DestUID); + int key = generateKey(request); + if (request.SubDevice.IsBroadcast) { - if (setTransactionCounter) - request.TransactionCounter = RDMSharp.Instance.getTransactionCounter(request.DestUID); - int key = generateKey(request); - if (request.SubDevice.IsBroadcast) + Logger?.LogTrace($"Send Subdevice-Broadcast Request: {request?.ToString()}"); + await _sendMethode.Invoke(request); + return new RequestResult(request, null, TimeSpan.Zero); // Broadcasts are not expected to return a response. + } + if (!buffer.TryAdd(key, new AsyncBufferBag(key, request))) + { + key += random.Next(); + buffer.TryAdd(key, new AsyncBufferBag(key, request)); + } + RDMMessage response = null; + Logger?.LogTrace($"Send Request: {request?.ToString()}"); + await _sendMethode.Invoke(request); + int count = 0; + do + { + if (this.IsDisposing || this.IsDisposed) + return new RequestResult(request, disposing: true); + + buffer.TryGetValue(key, out AsyncBufferBag bag); + response = bag?.Response; + if (response != null) + break; + if (request.Command != ERDM_Command.DISCOVERY_COMMAND) + await Task.Delay(5, _cts.Token); + else + await Task.Delay(GlobalTimers.Instance.DiscoveryTimeout, _cts.Token); + if (request.Command == ERDM_Command.NONE) { - Logger?.LogTrace($"Send Subdevice-Broadcast Request: {request?.ToString()}"); - await _sendMethode.Invoke(request); - return new RequestResult(request, null, TimeSpan.Zero); // Broadcasts are not expected to return a response. + throw new Exception("Command is not set"); } - if (!buffer.TryAdd(key, new AsyncBufferBag(key, request))) + count++; + if (count % 300 == 299) { - key += random.Next(); - buffer.TryAdd(key, new AsyncBufferBag(key, request)); + await Task.Delay(TimeSpan.FromTicks(random.Next(33, 777)), _cts.Token); + Logger?.LogTrace($"Retry Request: {request?.ToString()} ElapsedTime: {bag?.ElapsedTime}"); + await _sendMethode.Invoke(request); + await Task.Delay(TimeSpan.FromTicks(random.Next(33, 777)), _cts.Token); } - RDMMessage response = null; - Logger?.LogTrace($"Send Request: {request?.ToString()}"); - await _sendMethode.Invoke(request); - int count = 0; - do + if (count > 3 && request.Command == ERDM_Command.DISCOVERY_COMMAND) { - if (this.IsDisposing || this.IsDisposed) - return new RequestResult(request); - - buffer.TryGetValue(key, out AsyncBufferBag bag); - response = bag?.Response; - if (response != null) - break; - if (request.Command != ERDM_Command.DISCOVERY_COMMAND) - await Task.Delay(5, _cts.Token); - else - await Task.Delay(GlobalTimers.Instance.DiscoveryTimeout, _cts.Token); - if (request.Command == ERDM_Command.NONE) - { - throw new Exception("Command is not set"); - } - count++; - if (count % 300 == 299) - { - await Task.Delay(TimeSpan.FromTicks(random.Next(33, 777)), _cts.Token); - Logger?.LogTrace($"Retry Request: {request?.ToString()} ElapsedTime: {bag?.ElapsedTime}"); - await _sendMethode.Invoke(request); - await Task.Delay(TimeSpan.FromTicks(random.Next(33, 777)), _cts.Token); - } - if (count > 3 && request.Command == ERDM_Command.DISCOVERY_COMMAND) - { - Logger?.LogTrace($"Discovery request exceeded timeout"); - break; - } + Logger?.LogTrace($"Discovery request exceeded timeout"); + break; + } - if (count >= 900) - { - Logger?.LogTrace($"Timeout Request: {request?.ToString()} ElapsedTime: {bag?.ElapsedTime}"); - return new RequestResult(request); - } + if (count >= 900) + { + Logger?.LogTrace($"Timeout Request: {request?.ToString()} ElapsedTime: {bag?.ElapsedTime}"); + return new RequestResult(request, timeout: true); } - while (response == null); - buffer.TryRemove(key, out AsyncBufferBag bag2); - response = bag2.Response; - var result = new RequestResult(request, response, bag2.ElapsedTime); - Logger?.LogTrace($"Successful Request: {request?.ToString()} Response: {response?.ToString()} ElapsedTime: {bag2?.ElapsedTime}"); - return result; - } - catch (Exception ex) - { - Logger?.LogError(ex); } - return new RequestResult(request); + while (response == null); + buffer.TryRemove(key, out AsyncBufferBag bag2); + response = bag2.Response; + var result = new RequestResult(request, response, bag2.ElapsedTime); + Logger?.LogTrace($"Successful Request: {request?.ToString()} Response: {response?.ToString()} ElapsedTime: {bag2?.ElapsedTime}"); + return result; } - private int generateKey(RDMMessage request) - { - var command = (ERDM_Command)((byte)request.Command & ~(byte)ERDM_Command.RESPONSE); - if (command == ERDM_Command.DISCOVERY_COMMAND) - return random.Next(); + catch (Exception ex) + { + Logger?.LogError(ex); + } + return new RequestResult(request); + } + private int generateKey(RDMMessage request) + { + var command = (ERDM_Command)((byte)request.Command & ~(byte)ERDM_Command.RESPONSE); + if (command == ERDM_Command.DISCOVERY_COMMAND) + return random.Next(); - int key = (request.SourceUID.GetHashCode() + request.DestUID.GetHashCode())*111111111 - + (9 + request.SubDevice.GetHashCode()) * 45123 - + (123 + request.TransactionCounter.GetHashCode()) * 931 - + request.Parameter.GetHashCode()*67 - + command.GetHashCode()*7; - return key; - } + int key = (request.SourceUID.GetHashCode() + request.DestUID.GetHashCode()) * 111111111 + + (9 + request.SubDevice.GetHashCode()) * 45123 + + (123 + request.TransactionCounter.GetHashCode()) * 931 + + request.Parameter.GetHashCode() * 67 + + command.GetHashCode() * 7; + return key; + } - private class AsyncBufferBag - { - public readonly int Key; - - public readonly RDMMessage Request; - public readonly DateTime RequestTimestamp; + private class AsyncBufferBag + { + public readonly int Key; - public RDMMessage Response { get; private set; } - public DateTime? ResponseTimestamp { get; private set; } + public readonly RDMMessage Request; + public readonly DateTime RequestTimestamp; - private TimeSpan? elapsedTime; - public TimeSpan ElapsedTime - { - get - { - if (elapsedTime.HasValue) - return elapsedTime.Value; + public RDMMessage Response { get; private set; } + public DateTime? ResponseTimestamp { get; private set; } - return DateTime.UtcNow - RequestTimestamp; ; - } - private set - { - elapsedTime = value; - } - } - - public AsyncBufferBag(int key, RDMMessage request) - { - Request = request; - Response = null; - Key = key; - RequestTimestamp = DateTime.UtcNow; - } - public void SetResponse(RDMMessage response) + private TimeSpan? elapsedTime; + public TimeSpan ElapsedTime + { + get { - Response = response; - ResponseTimestamp = DateTime.UtcNow; - ElapsedTime = ResponseTimestamp.Value - RequestTimestamp; + if (elapsedTime.HasValue) + return elapsedTime.Value; + + return DateTime.UtcNow - RequestTimestamp; ; } + private set + { + elapsedTime = value; + } + } + + public AsyncBufferBag(int key, RDMMessage request) + { + Request = request; + Response = null; + Key = key; + RequestTimestamp = DateTime.UtcNow; + } + public void SetResponse(RDMMessage response) + { + Response = response; + ResponseTimestamp = DateTime.UtcNow; + ElapsedTime = ResponseTimestamp.Value - RequestTimestamp; } - } + } } \ No newline at end of file diff --git a/RDMSharp/RDM/Device/AbstractGeneratedRDMDevice.cs b/RDMSharp/RDM/Device/AbstractGeneratedRDMDevice.cs index 282532e..12c4032 100644 --- a/RDMSharp/RDM/Device/AbstractGeneratedRDMDevice.cs +++ b/RDMSharp/RDM/Device/AbstractGeneratedRDMDevice.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using RDMSharp.Metadata; +using RDMSharp.RDM.Device.Module; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -10,824 +11,528 @@ using static RDMSharp.RDMSharp; [assembly: InternalsVisibleTo("RDMSharpTests")] -namespace RDMSharp +namespace RDMSharp; + +public abstract class AbstractGeneratedRDMDevice : AbstractRDMDevice { - public abstract class AbstractGeneratedRDMDevice : AbstractRDMDevice + public sealed override bool IsGenerated => true; + public abstract bool SupportQueued { get; } + + private HashSet _parameters; + public IReadOnlySet Parameters { - public sealed override bool IsGenerated => true; - public abstract bool SupportQueued { get; } - public abstract bool SupportStatus { get; } - public virtual bool SupportRealTimeClock { get; } - #region DeviceInfoStuff - private HashSet _parameters; - public IReadOnlySet Parameters { get => _parameters; } - public abstract EManufacturer ManufacturerID { get; } - public abstract ushort DeviceModelID { get; } - public abstract ERDM_ProductCategoryCoarse ProductCategoryCoarse { get; } - public abstract ERDM_ProductCategoryFine ProductCategoryFine { get; } - public abstract uint SoftwareVersionID { get; } - #endregion - public abstract string DeviceModelDescription { get; } - public abstract GeneratedPersonality[] Personalities { get; } - - private readonly ConcurrentDictionary sensors = new ConcurrentDictionary(); - public sealed override IReadOnlyDictionary Sensors { get { return sensors.AsReadOnly(); } } - private ConcurrentDictionary sensorDef; - private ConcurrentDictionary sensorValue; - - public sealed override IReadOnlyDictionary Slots { get { return CurrentPersonality.HasValue ? Personalities?.FirstOrDefault(p => p.ID.Equals(CurrentPersonality.Value))?.Slots : null; } } - - private ConcurrentDictionary statusMessages = new ConcurrentDictionary(); - public sealed override IReadOnlyDictionary StatusMessages { get { return statusMessages.AsReadOnly(); } } - private ConcurrentDictionary controllerCommunicationCache = new ConcurrentDictionary(); - public abstract bool SupportDMXAddress { get; } - - private RDMDeviceInfo deviceInfo; - public sealed override RDMDeviceInfo DeviceInfo { get { return deviceInfo; } } - - private ConcurrentDictionary overflowCacheBags = new ConcurrentDictionary(); - - private ushort dmxAddress { get; set; } - public ushort? DMXAddress + get => _parameters; + private set { - get - { - if (!this.Parameters.Contains(ERDM_Parameter.DMX_START_ADDRESS)) - return null; - - return dmxAddress; - } - set - { - if (!this.Parameters.Contains(ERDM_Parameter.DMX_START_ADDRESS)) - { - dmxAddress = 0; - return; - } - if (!value.HasValue) - throw new NullReferenceException($"{DMXAddress} can't be null if {ERDM_Parameter.DMX_START_ADDRESS} is Supported"); - if (value.Value == 0) - throw new ArgumentOutOfRangeException($"{DMXAddress} can't 0 if {ERDM_Parameter.DMX_START_ADDRESS} is Supported"); + if (_parameters == value) + return; + _parameters = value.ToHashSet(); + this.OnPropertyChanged(); + } + } - if (dmxAddress == value.Value) - return; + #region DeviceInfoStuff + public abstract EManufacturer ManufacturerID { get; } + public abstract ushort DeviceModelID { get; } + public abstract ERDM_ProductCategoryCoarse ProductCategoryCoarse { get; } + public abstract ERDM_ProductCategoryFine ProductCategoryFine { get; } - dmxAddress = value.Value; - this.OnPropertyChanged(nameof(this.DMXAddress)); - this.updateDeviceInfo(); - } + public uint SoftwareVersionID + { + get + { + var softwareVersionModule = this.Modules.OfType().FirstOrDefault(); + return softwareVersionModule?.SoftwareVersionId ?? 0; } - public readonly string ManufacturerLabel; + } + public IReadOnlyCollection Personalities { get { return dmxPersonalityModule?.Personalities ?? Array.Empty(); } } + public sealed override IReadOnlyDictionary Sensors { get { return sensorsModule?.Sensors; } } + public sealed override IReadOnlyDictionary Slots { get { return slotsModule?.Slots; } } + public sealed override RDMDeviceInfo DeviceInfo { get { return deviceInfoModule?.DeviceInfo; } } - private string deviceLabel; - public string DeviceLabel + public ushort? DMXAddress + { + get { - get - { - return deviceLabel; - } - set - { - if (string.Equals(deviceLabel, value)) - return; + if (dmxStartAddressModule is null) + return null; - deviceLabel = value; - this.OnPropertyChanged(nameof(this.DeviceLabel)); - } + return dmxStartAddressModule.DMXAddress; } - - private byte currentPersonality; - public byte? CurrentPersonality + set { - get - { - if (!this.Parameters.Contains(ERDM_Parameter.DMX_PERSONALITY)) - return null; - - return currentPersonality; - } - set - { - if (!this.Parameters.Contains(ERDM_Parameter.DMX_PERSONALITY)) - { - currentPersonality = 0; - return; - } - if (!value.HasValue) - throw new NullReferenceException($"{CurrentPersonality} can't be null if {ERDM_Parameter.DMX_PERSONALITY} is Supported"); - if (value.Value == 0) - throw new ArgumentOutOfRangeException($"{CurrentPersonality} can't 0 if {ERDM_Parameter.DMX_PERSONALITY} is Supported"); - - if (!this.Personalities.Any(p => p.ID == value.Value)) - throw new ArgumentOutOfRangeException($"No Personality found with ID: {value.Value}"); - - if (currentPersonality == value) - return; + if (dmxStartAddressModule is null) + return; + if (dmxStartAddressModule.DMXAddress == value) + return; - currentPersonality = value.Value; - this.OnPropertyChanged(nameof(this.CurrentPersonality)); - this.updateDeviceInfo(); - } + dmxStartAddressModule.DMXAddress = value; + this.OnPropertyChanged(nameof(this.DMXAddress)); } - private bool discoveryMuted; - public bool DiscoveryMuted + } + + public byte? CurrentPersonality + { + get { - get - { - return discoveryMuted; - } - private set - { - if (discoveryMuted == value) - return; - discoveryMuted = value; - OnPropertyChanged(nameof(DiscoveryMuted)); - } + return dmxPersonalityModule.CurrentPersonality; } - - private bool identify; - public bool Identify + set { - get - { - return identify; - } - set - { - if (string.Equals(identify, value)) - return; + if (dmxPersonalityModule is null) + return; + if (dmxPersonalityModule.CurrentPersonality == value) + return; - identify = value; - this.OnPropertyChanged(nameof(this.Identify)); - } + dmxPersonalityModule.CurrentPersonality = value; + this.OnPropertyChanged(nameof(this.CurrentPersonality)); } + } + #endregion + public sealed override IReadOnlyDictionary StatusMessages { get { return statusMessageModule?.StatusMessages; } } - private string softwareVersionLabel; - public string SoftwareVersionLabel - { - get - { - return softwareVersionLabel; - } - protected set - { - if (string.Equals(softwareVersionLabel, value)) - return; + private ConcurrentDictionary controllerCommunicationCache = new ConcurrentDictionary(); + private ConcurrentDictionary overflowCacheBags = new ConcurrentDictionary(); - softwareVersionLabel = value; - this.OnPropertyChanged(nameof(this.SoftwareVersionLabel)); - } - } + private readonly IReadOnlyCollection _modules; + public IReadOnlyCollection Modules { get => _modules; } - private string bootSoftwareVersionLabel; - public string BootSoftwareVersionLabel - { - get - { - return bootSoftwareVersionLabel; - } - protected set - { - if (string.Equals(bootSoftwareVersionLabel, value)) - return; + protected readonly DeviceInfoModule deviceInfoModule; + protected readonly IdentifyDeviceModule identifyDeviceModule; + protected readonly DMX_StartAddressModule? dmxStartAddressModule; + protected readonly DMX_PersonalityModule? dmxPersonalityModule; + protected readonly SlotsModule? slotsModule; + protected readonly SensorsModule? sensorsModule; + protected readonly StatusMessageModule? statusMessageModule; - bootSoftwareVersionLabel = value; - this.OnPropertyChanged(nameof(this.BootSoftwareVersionLabel)); - } - } - - public DateTime realTimeClock; - public DateTime RealTimeClock + private bool discoveryMuted; + public bool DiscoveryMuted + { + get { - get - { - return realTimeClock; - } - private set - { - if (DateTime.Equals(realTimeClock, value)) - return; - - realTimeClock = value; - this.OnPropertyChanged(nameof(this.RealTimeClock)); - } + return discoveryMuted; } - - private bool _initialized = false; - - protected AbstractGeneratedRDMDevice(UID uid, ERDM_Parameter[] parameters, string manufacturer = null, Sensor[] sensors = null, IRDMDevice[] subDevices = null) : this(uid, SubDevice.Root, parameters, manufacturer, sensors, subDevices) + private set { + if (discoveryMuted == value) + return; + discoveryMuted = value; + OnPropertyChanged(nameof(DiscoveryMuted)); } - protected AbstractGeneratedRDMDevice(UID uid, SubDevice subDevice, ERDM_Parameter[] parameters, string manufacturer = null, Sensor[] sensors = null) : this(uid, subDevice, parameters, manufacturer, sensors, null) + } + + public bool Identify + { + get { + return identifyDeviceModule.Identify; } - private AbstractGeneratedRDMDevice(UID uid, SubDevice subDevice, ERDM_Parameter[] parameters, string manufacturer = null, Sensor[] sensors = null, IRDMDevice[] subDevices = null) : base(uid, subDevice, subDevices) + set { - if (!((ushort)ManufacturerID).Equals(uid.ManufacturerID)) - throw new Exception($"{uid.ManufacturerID} not match the {ManufacturerID}"); - - RDMSharp.Instance.RequestReceivedEvent += Instance_RequestReceivedEvent; - - #region Parameters - var _params = new HashSet(); - if (parameters != null && parameters.Length != 0) - foreach (var p in parameters) - _params.Add(p); + if (string.Equals(identifyDeviceModule.Identify, value)) + return; - if (SupportQueued) - _params.Add(ERDM_Parameter.QUEUED_MESSAGE); - if (SupportStatus) - { - _params.Add(ERDM_Parameter.STATUS_MESSAGES); - _params.Add(ERDM_Parameter.CLEAR_STATUS_ID); - } + identifyDeviceModule.Identify = value; + this.OnPropertyChanged(); + } + } - _params.Add(ERDM_Parameter.DEVICE_INFO); - _params.Add(ERDM_Parameter.SUPPORTED_PARAMETERS); - _params.Add(ERDM_Parameter.SOFTWARE_VERSION_LABEL); - _params.Add(ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID); - _params.Add(ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL); - _params.Add(ERDM_Parameter.DEVICE_LABEL); - _params.Add(ERDM_Parameter.DEVICE_MODEL_DESCRIPTION); - _params.Add(ERDM_Parameter.MANUFACTURER_LABEL); - _params.Add(ERDM_Parameter.IDENTIFY_DEVICE); - if (SupportRealTimeClock) - _params.Add(ERDM_Parameter.REAL_TIME_CLOCK); - if (SupportDMXAddress) - _params.Add(ERDM_Parameter.DMX_START_ADDRESS); - if ((Personalities?.Length ?? 0) != 0) - { - _params.Add(ERDM_Parameter.DMX_PERSONALITY); - _params.Add(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION); - _params.Add(ERDM_Parameter.SLOT_INFO); - _params.Add(ERDM_Parameter.SLOT_DESCRIPTION); - _params.Add(ERDM_Parameter.DEFAULT_SLOT_VALUE); - } + private bool _initialized = false; - _parameters = _params; - if (SupportRealTimeClock) - trySetParameter(ERDM_Parameter.REAL_TIME_CLOCK, new RDMRealTimeClock(DateTime.Now)); - trySetParameter(ERDM_Parameter.SUPPORTED_PARAMETERS, Parameters.ToArray()); - trySetParameter(ERDM_Parameter.IDENTIFY_DEVICE, Identify); - #endregion + protected AbstractGeneratedRDMDevice(UID uid, IRDMDevice[] subDevices = null, IReadOnlyCollection modules = null) : this(uid, SubDevice.Root, subDevices, modules) + { + } + protected AbstractGeneratedRDMDevice(UID uid, SubDevice subDevice, IReadOnlyCollection modules = null) : this(uid, subDevice, null, modules) + { + } + private AbstractGeneratedRDMDevice(UID uid, SubDevice subDevice, IRDMDevice[] subDevices = null, IReadOnlyCollection modules = null) : base(uid, subDevice, subDevices) + { + if (!((ushort)ManufacturerID).Equals(uid.ManufacturerID)) + throw new Exception($"{uid.ManufacturerID} not match the {ManufacturerID}"); - #region ManufacturerLabel - string _manufacturer = Enum.GetName(typeof(EManufacturer), (EManufacturer)uid.ManufacturerID); + RDMSharp.Instance.RequestReceivedEvent += Instance_RequestReceivedEvent; - if (string.IsNullOrWhiteSpace(_manufacturer)) - _manufacturer = manufacturer; - if (string.IsNullOrWhiteSpace(_manufacturer)) - throw new ArgumentNullException($"{manufacturer} not set, needed in case the Manufacturer is not Part of {typeof(EManufacturer).Name}"); + List moduleList = new List(); + identifyDeviceModule = new IdentifyDeviceModule(); + moduleList.Add(identifyDeviceModule); - ManufacturerLabel = _manufacturer; - this.OnPropertyChanged(nameof(this.ManufacturerLabel)); - #endregion + if (modules is not null) + moduleList.AddRange(modules); - #region DeviceModelDescription - this.OnPropertyChanged(nameof(this.DeviceModelDescription)); - #endregion + deviceInfoModule = new DeviceInfoModule(); + moduleList.Add(deviceInfoModule); + _modules = moduleList.AsReadOnly(); + dmxStartAddressModule = _modules.OfType().FirstOrDefault(); + dmxPersonalityModule = _modules.OfType().FirstOrDefault(); + slotsModule = _modules.OfType().FirstOrDefault(); + sensorsModule = _modules.OfType().FirstOrDefault(); + statusMessageModule = _modules.OfType().FirstOrDefault(); + if (dmxPersonalityModule is not null)//Remove after Refactoring to Modules + dmxPersonalityModule.PropertyChanged += DmxPersonalityModule_PropertyChanged; - #region DeviceLabel - this.DeviceLabel = this.DeviceModelDescription; - #endregion + var _params = new HashSet(); - #region Personalities - if (Personalities != null) - { - if (Personalities.Length >= byte.MaxValue) - throw new ArgumentOutOfRangeException($"There to many {Personalities}! Maximum is {byte.MaxValue - 1}"); + if (SupportQueued) + _params.Add(ERDM_Parameter.QUEUED_MESSAGE); - if (Personalities.Length != 0) - { - var persDesc = new ConcurrentDictionary(); - foreach (var gPers in Personalities) - if (!persDesc.TryAdd(gPers.ID, (RDMDMXPersonalityDescription)gPers)) - throw new Exception($"{gPers.ID} already used as {nameof(gPers.ID)}"); + _params.Add(ERDM_Parameter.SUPPORTED_PARAMETERS); - trySetParameter(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION, persDesc); - } - CurrentPersonality = 1; - } - #endregion + foreach (IModule module in _modules) + foreach (var parameter in module.SupportedParameters) + _params.Add(parameter); - #region Sensors + Parameters = _params; - if (sensors != null) - this.AddSensors(sensors); + foreach (IModule module in _modules) + if (module is AbstractModule aModule) + aModule.SetParentDevice(this); - #endregion + trySetParameter(ERDM_Parameter.SUPPORTED_PARAMETERS, Parameters.ToArray()); - #region StatusMessage - if (SupportStatus) - trySetParameter(ERDM_Parameter.STATUS_MESSAGES, new RDMStatusMessage[0]); - #endregion + _initialized = true; + } - #region DMX-Address - if (Parameters.Contains(ERDM_Parameter.DMX_START_ADDRESS)) - DMXAddress = 1; - #endregion + private void DmxPersonalityModule_PropertyChanged(object sender, PropertyChangedEventArgs e)//Remove after Refactoring to Modules + { + OnPropertyChanged(e.PropertyName); + } - #region RealTimeClock - if (Parameters.Contains(ERDM_Parameter.REAL_TIME_CLOCK)) - Task.Run(async () => - { - - while (true) - { - double last = 0; - await Task.Delay(100); - var dateTime = DateTime.UtcNow.TimeOfDay.TotalSeconds; - if (Math.Abs(dateTime - last) > 1) - { - last = dateTime; - RealTimeClock = DateTime.Now; - } - } - }); - #endregion + protected bool trySetParameter(ERDM_Parameter parameter, object value) + { + if (!this.Parameters.Contains(parameter)) + throw new NotSupportedException($"The Parameter: {parameter}, is not Supported"); - updateDeviceInfo(); - _initialized = true; - } + setParameterValue(parameter, value); + return true; + } + public bool TrySetParameter(ERDM_Parameter parameter, object value, bool throwException = true) + { - private void updateDeviceInfo() + if (!this.Parameters.Contains(parameter)) { - var info = new RDMDeviceInfo(1, - 0, - DeviceModelID, - ProductCategoryCoarse, - ProductCategoryFine, - SoftwareVersionID, - dmx512Footprint: Personalities.FirstOrDefault(p => p.ID == currentPersonality)?.SlotCount ?? 0, - dmx512CurrentPersonality: currentPersonality, - dmx512NumberOfPersonalities: (byte)(Personalities?.Length ?? 0), - dmx512StartAddress: dmxAddress, - subDeviceCount: (ushort)(SubDevices?.Where(sd=>!sd.Subdevice.IsRoot).Count() ?? 0), - sensorCount: (byte)(Sensors?.Count ?? 0)); - updateDeviceInfo(info); + if (throwException) + throw new NotSupportedException($"The Device not support the Parameter: {parameter}"); + return false; } - private void updateDeviceInfo(RDMDeviceInfo value) + switch (parameter) { - if (RDMDeviceInfo.Equals(deviceInfo, value)) - return; + case ERDM_Parameter.DMX_START_ADDRESS: + case ERDM_Parameter.DEVICE_LABEL: + if (throwException) + throw new NotSupportedException($"You have no permission to set the Parameter: {parameter}, use the public Propertys to set them"); + return false; - deviceInfo = value; - this.OnPropertyChanged(nameof(this.DeviceInfo)); + case ERDM_Parameter.DEVICE_INFO: + case ERDM_Parameter.DEVICE_MODEL_DESCRIPTION: + case ERDM_Parameter.MANUFACTURER_LABEL: + case ERDM_Parameter.QUEUED_MESSAGE: + case ERDM_Parameter.SUPPORTED_PARAMETERS: + case ERDM_Parameter.SLOT_DESCRIPTION: + case ERDM_Parameter.SLOT_INFO: + case ERDM_Parameter.DEFAULT_SLOT_VALUE: + case ERDM_Parameter.SENSOR_DEFINITION: + case ERDM_Parameter.SENSOR_VALUE: + if (throwException) + throw new NotSupportedException($"The Protocoll not allow to set the Parameter: {parameter}"); + return false; } - protected void AddSensors(params Sensor[] @sensors) + var parameterBag = new ParameterBag(parameter, UID.ManufacturerID, DeviceInfo?.DeviceModelId, DeviceInfo?.SoftwareVersionId); + var define = MetadataFactory.GetDefine(parameterBag); + if (define != null) { - if (sensors == null) - throw new ArgumentNullException(); - - if (sensorDef is null) - sensorDef = new ConcurrentDictionary(); - if (sensorValue is null) - sensorValue = new ConcurrentDictionary(); - foreach (var sensor in @sensors) + if (!define.SetRequest.HasValue) { - if (sensor == null) - throw new ArgumentNullException(nameof(sensor)); - if (this.sensors.ContainsKey(sensor.SensorId)) - throw new ArgumentOutOfRangeException($"The Sensor with the ID: {sensor.SensorId} already exists"); + if (throwException) + throw new NotSupportedException($"The Protocoll not allow to set the Parameter: {parameter}"); + return false; + } - if (this.sensors.TryAdd(sensor.SensorId, sensor)) + try + { + if (!define.SetRequest.HasValue) + throw new NotSupportedException($"The Protocoll not allow to set the Parameter: {parameter}"); + else { - if (!sensorDef.TryAdd(sensor.SensorId, (RDMSensorDefinition)sensor)) - 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)}"); - - sensor.PropertyChanged += Sensor_PropertyChanged; + byte[] data = MetadataFactory.ParsePayloadToData(define, Metadata.JSON.Command.ECommandDublicate.SetRequest, DataTreeBranch.FromObject(value, null, parameterBag, ERDM_Command.SET_COMMAND)).First(); + var obj = MetadataFactory.ParseDataToPayload(define, Metadata.JSON.Command.ECommandDublicate.SetRequest, data); + if (!object.Equals(value, obj)) + return false; } } - - var _sensors = Sensors.Values.ToArray(); - if (_sensors.Length >= byte.MaxValue) - throw new ArgumentOutOfRangeException($"There to many {Sensors}! Maximum is {byte.MaxValue - 1}"); - if (_sensors.Length > 0) + catch (Exception e) { - if (_sensors.Min(s => s.SensorId) != 0) - throw new ArgumentOutOfRangeException($"The first Sensor should have the ID: 0, but is({_sensors.Min(s => s.SensorId)})"); - if (_sensors.Max(s => s.SensorId) + 1 != _sensors.Length) - throw new ArgumentOutOfRangeException($"The last Sensor should have the ID: {_sensors.Max(s => s.SensorId) + 1}, but is({_sensors.Max(s => s.SensorId)})"); - - if (_sensors.Select(s => s.SensorId).Distinct().Count() != _sensors.Length) - throw new ArgumentOutOfRangeException($"Some Sensor-IDs are used more then onse"); - - setParameterValue(ERDM_Parameter.SENSOR_DEFINITION, sensorDef); - setParameterValue(ERDM_Parameter.SENSOR_VALUE, sensorValue); + Logger?.LogError(e, string.Empty); + return false; } - - updateSupportedParametersOnAddRemoveSensors(); - updateDeviceInfo(); } - protected void RemoveSensors(params Sensor[] @sensors) - { - foreach (var sensor in @sensors) - { - if (sensor == null) - throw new ArgumentNullException(nameof(sensor)); - if (!this.sensors.ContainsKey(sensor.SensorId)) - throw new ArgumentOutOfRangeException($"The Sensor with the ID: {sensor.SensorId} not exists"); - if (this.sensors.TryRemove(sensor.SensorId, out _)) - { - sensor.PropertyChanged -= Sensor_PropertyChanged; - if (parameterValues.TryGetValue(ERDM_Parameter.SENSOR_DEFINITION, out object value_d) && value_d is ConcurrentDictionary sensorDef) - { - if (sensorDef.TryRemove(sensor.SensorId, out _)) - setParameterValue(ERDM_Parameter.SENSOR_DEFINITION, sensorDef); - } - if (parameterValues.TryGetValue(ERDM_Parameter.SENSOR_VALUE, out object value_v) && value_v is ConcurrentDictionary sensorValue) - { - if (sensorValue.TryRemove(sensor.SensorId, out _)) - setParameterValue(ERDM_Parameter.SENSOR_VALUE, sensorValue); - } - } - } - if (sensorDef?.IsEmpty ?? false) - sensorDef = null; - if (sensorValue?.IsEmpty ?? false) - sensorValue = null; + return this.trySetParameter(parameter, value); + } + protected sealed override void OnPropertyChanged([CallerMemberName] string property = null) + { + switch (property) + { + case nameof(DeviceInfo): + trySetParameter(ERDM_Parameter.DEVICE_INFO, this.DeviceInfo); + trySetParameter(ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID, this.DeviceInfo.SoftwareVersionId); + break; + //case nameof(CurrentPersonality): + // var slots = Personalities.First(p => p.ID == this.CurrentPersonality).Slots.Count; + // var slotInfos = new RDMSlotInfo[slots]; + // var slotDesc = new ConcurrentDictionary(); + // var slotDefault = new RDMDefaultSlotValue[slots]; + // foreach (var s in Personalities.First(p => p.ID == this.CurrentPersonality).Slots) + // { + // Slot slot = s.Value; + // slotInfos[slot.SlotId] = new RDMSlotInfo(slot.SlotId, slot.Type, slot.Category); + // slotDesc.TryAdd(slot.SlotId, new RDMSlotDescription(slot.SlotId, slot.Description)); + // slotDefault[slot.SlotId] = new RDMDefaultSlotValue(slot.SlotId, slot.DefaultValue); + // } + // trySetParameter(ERDM_Parameter.SLOT_INFO, slotInfos); + // trySetParameter(ERDM_Parameter.SLOT_DESCRIPTION, slotDesc); + // trySetParameter(ERDM_Parameter.DEFAULT_SLOT_VALUE, slotDefault); + // break; + } + base.OnPropertyChanged(property); + } - setParameterValue(ERDM_Parameter.SENSOR_DEFINITION, sensorDef); - setParameterValue(ERDM_Parameter.SENSOR_VALUE, sensorValue); - updateSupportedParametersOnAddRemoveSensors(); - updateDeviceInfo(); + public bool SetParameter(ERDM_Parameter parameter, object value = null) + { + setParameterValue(parameter, value); + return true; + } + internal void setParameterValue(ERDM_Parameter parameter, object value, object index = null) + { + bool notNew = false; + if (value is null) + { + parameterValues.TryRemove(parameter, out object oldValue); + return; } - - private void updateSupportedParametersOnAddRemoveSensors() + bool raiseAddedEvent = false; + bool raiseUpdatedEvent = false; + object? ov = null; + parameterValues.AddOrUpdate(parameter, (_) => { - var oldParameters = Parameters; - if (!this.sensors.IsEmpty) + try { - HashSet _params = Parameters.ToHashSet(); - _params.Add(ERDM_Parameter.SENSOR_DEFINITION); - _params.Add(ERDM_Parameter.SENSOR_VALUE); - _parameters = _params; + return value; } - else if ( - Parameters.Contains(ERDM_Parameter.SENSOR_DEFINITION) || - Parameters.Contains(ERDM_Parameter.SENSOR_VALUE) || - Parameters.Contains(ERDM_Parameter.RECORD_SENSORS) || - Parameters.Contains(ERDM_Parameter.SENSOR_TYPE_CUSTOM) || - Parameters.Contains(ERDM_Parameter.SENSOR_UNIT_CUSTOM)) + finally { - HashSet _params = Parameters.ToHashSet(); - _params.RemoveWhere(p => - p == ERDM_Parameter.SENSOR_DEFINITION || - p == ERDM_Parameter.SENSOR_VALUE || - p == ERDM_Parameter.RECORD_SENSORS || - p == ERDM_Parameter.SENSOR_TYPE_CUSTOM || - p == ERDM_Parameter.SENSOR_UNIT_CUSTOM); - _parameters = _params; + raiseAddedEvent = true; } - - if (sensors.Values.Any(s => s.RecordedValueSupported) && !Parameters.Contains(ERDM_Parameter.RECORD_SENSORS)) + }, (o, p) => + { + try { - HashSet _params = Parameters.ToHashSet(); - _params.Add(ERDM_Parameter.RECORD_SENSORS); - _parameters = _params; + ov = p; + if (object.Equals(ov, value) && value is not ConcurrentDictionary) + notNew = true; + return value; } - else if (!sensors.Values.Any(s => s.RecordedValueSupported) && Parameters.Contains(ERDM_Parameter.RECORD_SENSORS)) + finally { - HashSet _params = Parameters.ToHashSet(); - _params.RemoveWhere(sensors => sensors == ERDM_Parameter.RECORD_SENSORS); - _parameters = _params; + raiseUpdatedEvent = true; } + }); - if (!Parameters.SequenceEqual(oldParameters)) - trySetParameter(ERDM_Parameter.SUPPORTED_PARAMETERS, Parameters.ToArray()); - } - - private void Sensor_PropertyChanged(object sender, PropertyChangedEventArgs e) + try { - if (sender is not Sensor sensor) + if (notNew) return; - - switch (e.PropertyName) + if (parameter != ERDM_Parameter.SLOT_DESCRIPTION) { - case nameof(Sensor.Type): - case nameof(Sensor.Unit): - case nameof(Sensor.Prefix): - case nameof(Sensor.RangeMaximum): - case nameof(Sensor.RangeMinimum): - case nameof(Sensor.NormalMaximum): - case nameof(Sensor.NormalMinimum): - case nameof(Sensor.LowestHighestValueSupported): - case nameof(Sensor.RecordedValueSupported): - sensorDef.AddOrUpdate(sensor.SensorId, (RDMSensorDefinition)sensor, (o1, o2) => (RDMSensorDefinition)sensor); - setParameterValue(ERDM_Parameter.SENSOR_DEFINITION, sensorDef, sensor.SensorId); - break; - case nameof(Sensor.PresentValue): - case nameof(Sensor.LowestValue): - case nameof(Sensor.HighestValue): - case nameof(Sensor.RecordedValue): - sensorValue.AddOrUpdate(sensor.SensorId, (RDMSensorValue)sensor, (o1, o2) => (RDMSensorValue)sensor); - setParameterValue(ERDM_Parameter.SENSOR_VALUE, sensorValue, sensor.SensorId); - break; - } - } - - protected bool trySetParameter(ERDM_Parameter parameter, object value) - { - if (!this.Parameters.Contains(parameter)) - throw new NotSupportedException($"The Parameter: {parameter}, is not Supported"); - - setParameterValue(parameter, value); - return true; - } - public bool TrySetParameter(ERDM_Parameter parameter, object value, bool throwException = true) - { - - if (!this.Parameters.Contains(parameter)) - { - if (throwException) - throw new NotSupportedException($"The Device not support the Parameter: {parameter}"); - return false; + updateParameterBag(parameter, index); + return; } - - switch (parameter) + if (value is ConcurrentDictionary dict) { - case ERDM_Parameter.DMX_START_ADDRESS: - case ERDM_Parameter.DEVICE_LABEL: - if (throwException) - throw new NotSupportedException($"You have no permission to set the Parameter: {parameter}, use the public Propertys to set them"); - return false; - - case ERDM_Parameter.DEVICE_INFO: - case ERDM_Parameter.DEVICE_MODEL_DESCRIPTION: - case ERDM_Parameter.MANUFACTURER_LABEL: - case ERDM_Parameter.QUEUED_MESSAGE: - case ERDM_Parameter.SUPPORTED_PARAMETERS: - case ERDM_Parameter.SLOT_DESCRIPTION: - case ERDM_Parameter.SLOT_INFO: - case ERDM_Parameter.DEFAULT_SLOT_VALUE: - case ERDM_Parameter.SENSOR_DEFINITION: - case ERDM_Parameter.SENSOR_VALUE: - if (throwException) - throw new NotSupportedException($"The Protocoll not allow to set the Parameter: {parameter}"); - return false; + foreach (var p in dict) + updateParameterBag(parameter, p.Key); } - - var parameterBag = new ParameterBag(parameter, UID.ManufacturerID, DeviceInfo?.DeviceModelId, DeviceInfo?.SoftwareVersionId); - var define = MetadataFactory.GetDefine(parameterBag); - if (define != null) - { - if (!define.SetRequest.HasValue) - { - if (throwException) - throw new NotSupportedException($"The Protocoll not allow to set the Parameter: {parameter}"); - return false; - } - - 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.ECommandDublicate.SetRequest, DataTreeBranch.FromObject(value, null, parameterBag, ERDM_Command.SET_COMMAND)).First(); - var obj = MetadataFactory.ParseDataToPayload(define, Metadata.JSON.Command.ECommandDublicate.SetRequest, data); - if (!object.Equals(value, obj)) - return false; - } - } - catch (Exception e) - { - Logger?.LogError(e, string.Empty); - return false; - } - } - - return this.trySetParameter(parameter, value); + return; } - protected sealed override void OnPropertyChanged(string property) + finally { - switch (property) - { - case nameof(DeviceInfo): - trySetParameter(ERDM_Parameter.DEVICE_INFO, this.DeviceInfo); - trySetParameter(ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID, this.DeviceInfo.SoftwareVersionId); - break; - case nameof(DeviceModelDescription): - trySetParameter(ERDM_Parameter.DEVICE_MODEL_DESCRIPTION, this.DeviceModelDescription); - break; - case nameof(DMXAddress): - trySetParameter(ERDM_Parameter.DMX_START_ADDRESS, this.DMXAddress); - break; - case nameof(Identify): - trySetParameter(ERDM_Parameter.IDENTIFY_DEVICE, this.Identify); - break; - case nameof(CurrentPersonality): - trySetParameter(ERDM_Parameter.DMX_PERSONALITY, new RDMDMXPersonality(this.currentPersonality, (byte)(Personalities?.Length ?? 0))); - - var slots = Personalities.First(p => p.ID == this.currentPersonality).Slots.Count; - var slotInfos = new RDMSlotInfo[slots]; - var slotDesc = new ConcurrentDictionary(); - var slotDefault = new RDMDefaultSlotValue[slots]; - foreach (var s in Personalities.First(p => p.ID == this.currentPersonality).Slots) - { - Slot slot = s.Value; - slotInfos[slot.SlotId] = new RDMSlotInfo(slot.SlotId, slot.Type, slot.Category); - slotDesc.TryAdd(slot.SlotId, new RDMSlotDescription(slot.SlotId, slot.Description)); - slotDefault[slot.SlotId] = new RDMDefaultSlotValue(slot.SlotId, slot.DefaultValue); - } - trySetParameter(ERDM_Parameter.SLOT_INFO, slotInfos); - trySetParameter(ERDM_Parameter.SLOT_DESCRIPTION, slotDesc); - trySetParameter(ERDM_Parameter.DEFAULT_SLOT_VALUE, slotDefault); - break; - case nameof(DeviceLabel): - trySetParameter(ERDM_Parameter.DEVICE_LABEL, this.DeviceLabel); - break; - case nameof(ManufacturerLabel): - trySetParameter(ERDM_Parameter.MANUFACTURER_LABEL, this.ManufacturerLabel); - break; - case nameof(SoftwareVersionLabel): - trySetParameter(ERDM_Parameter.SOFTWARE_VERSION_LABEL, this.SoftwareVersionLabel); - break; - case nameof(BootSoftwareVersionLabel): - trySetParameter(ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL, this.BootSoftwareVersionLabel); - break; - case nameof(RealTimeClock): - trySetParameter(ERDM_Parameter.REAL_TIME_CLOCK, new RDMRealTimeClock(this.RealTimeClock)); - break; - } - base.OnPropertyChanged(property); + if (raiseAddedEvent) + InvokeParameterValueAdded(new ParameterValueAddedEventArgs(parameter, value, index)); + if (raiseUpdatedEvent) + InvokeParameterValueChanged(new ParameterValueChangedEventArgs(parameter, value, ov, index)); } + } - - public bool SetParameter(ERDM_Parameter parameter, object value = null) - { - setParameterValue(parameter, value); - return true; - } - private void setParameterValue(ERDM_Parameter parameter, object value, object index=null) + private void Instance_RequestReceivedEvent(object sender, RequestReceivedEventArgs e) + { + RDMMessage response = null; + if ((e.Request.DestUID.IsBroadcast || e.Request.DestUID == UID) && !e.Request.Command.HasFlag(ERDM_Command.RESPONSE)) { - switch (parameter) + if (e.Request.SubDevice.IsBroadcast) { - case ERDM_Parameter.DEVICE_INFO when value is RDMDeviceInfo _deviceInfo: - deviceInfo = _deviceInfo; - goto default; - - default: - bool notNew = false; - if (value is null) - { - parameterValues.TryRemove(parameter, out object oldValue); - return; - } - parameterValues.AddOrUpdate(parameter, value, (o, p) => - { - if (object.Equals(p, value)&& value is not ConcurrentDictionary) - notNew = true; - return value; - }); - if (notNew) - return; - if (parameter != ERDM_Parameter.SLOT_DESCRIPTION) - { - updateParameterBag(parameter, index); - return; - } - if(value is ConcurrentDictionary dict) - { - foreach (var p in dict) - updateParameterBag(parameter, p.Key); - } - return; + foreach (var sd in this.SubDevices) + _ = processRequestMessage(e.Request); //Drop response on Broadcast + return; } - } + AbstractGeneratedRDMDevice sds = null; + if (e.Request.SubDevice == this.Subdevice) + sds = this; + else + sds = this.SubDevices?.OfType().FirstOrDefault(sd => sd.Subdevice == e.Request.SubDevice); - #region SendReceive Pipeline - private void Instance_RequestReceivedEvent(object sender, RequestReceivedEventArgs e) - { - RDMMessage response = null; - if ((e.Request.DestUID.IsBroadcast || e.Request.DestUID == UID) && !e.Request.Command.HasFlag(ERDM_Command.RESPONSE)) - { - if (e.Request.SubDevice.IsBroadcast) - { - foreach (var sd in this.SubDevices) - _ = processRequestMessage(e.Request); //Drop response on Broadcast - return; - } - - AbstractGeneratedRDMDevice sds = null; - if (e.Request.SubDevice == this.Subdevice) - sds = this; - else - sds = this.SubDevices?.OfType().FirstOrDefault(sd => sd.Subdevice == e.Request.SubDevice); - - if (sds != null) - response = sds.processRequestMessage(e.Request); - } - if (e.Request.Command != ERDM_Command.DISCOVERY_COMMAND) - e.Response = response; - else if (response != null && response.Command == ERDM_Command.DISCOVERY_COMMAND_RESPONSE) - RDMSharp.Instance.SendMessage(response); + if (sds != null) + response = sds.processRequestMessage(e.Request); } -#endregion - protected async Task OnReceiveRDMMessage(RDMMessage rdmMessage) - { - if ((rdmMessage.DestUID.IsBroadcast || rdmMessage.DestUID == UID) && !rdmMessage.Command.HasFlag(ERDM_Command.RESPONSE)) - { - if (rdmMessage.SubDevice.IsBroadcast || rdmMessage.SubDevice == this.Subdevice) - await RDMSharp.Instance.SendMessage(processRequestMessage(rdmMessage)); - } - } - protected sealed override async Task OnResponseMessage(RDMMessage rdmMessage) + if (e.Request.Command != ERDM_Command.DISCOVERY_COMMAND) + e.Response = response; + else if (response != null && response.Command == ERDM_Command.DISCOVERY_COMMAND_RESPONSE) + RDMSharp.Instance.SendMessage(response); + } + + protected async Task OnReceiveRDMMessage(RDMMessage rdmMessage) + { + if ((rdmMessage.DestUID.IsBroadcast || rdmMessage.DestUID == UID) && !rdmMessage.Command.HasFlag(ERDM_Command.RESPONSE)) { - await OnReceiveRDMMessage(rdmMessage); - await base.OnResponseMessage(rdmMessage); + if (rdmMessage.SubDevice.IsBroadcast || rdmMessage.SubDevice == this.Subdevice) + await RDMSharp.Instance.SendMessage(processRequestMessage(rdmMessage)); } + } + protected sealed override async Task OnResponseMessage(RDMMessage rdmMessage) + { + await OnReceiveRDMMessage(rdmMessage); + await base.OnResponseMessage(rdmMessage); + } - protected RDMMessage processRequestMessage(RDMMessage rdmMessage) + protected RDMMessage processRequestMessage(RDMMessage rdmMessage) + { + RDMMessage response = null; + try { - RDMMessage response = null; - try + var controllerCache = getControllerCommunicationCache(rdmMessage.SourceUID); + controllerCache.Seen(); + if (rdmMessage.Command == ERDM_Command.DISCOVERY_COMMAND) { - var controllerCache = getControllerCommunicationCache(rdmMessage.SourceUID); - controllerCache.Seen(); - if (rdmMessage.Command == ERDM_Command.DISCOVERY_COMMAND) + switch (rdmMessage.Parameter) { - switch (rdmMessage.Parameter) - { - case ERDM_Parameter.DISC_MUTE: - DiscoveryMuted = true; - response = new RDMMessage - { - Parameter = ERDM_Parameter.DISC_MUTE, - Command = ERDM_Command.DISCOVERY_COMMAND_RESPONSE, - SourceUID = UID, - DestUID = rdmMessage.SourceUID, - ParameterData = new DiscMuteUnmuteResponse().ToPayloadData() - }; - return rdmMessage.DestUID != UID.Broadcast ? response : null; - case ERDM_Parameter.DISC_UN_MUTE: - DiscoveryMuted = false; + case ERDM_Parameter.DISC_MUTE: + DiscoveryMuted = true; + response = new RDMMessage + { + Parameter = ERDM_Parameter.DISC_MUTE, + Command = ERDM_Command.DISCOVERY_COMMAND_RESPONSE, + SourceUID = UID, + DestUID = rdmMessage.SourceUID, + ParameterData = new DiscMuteUnmuteResponse().ToPayloadData() + }; + return rdmMessage.DestUID != UID.Broadcast ? response : null; + case ERDM_Parameter.DISC_UN_MUTE: + DiscoveryMuted = false; + response = new RDMMessage + { + Parameter = ERDM_Parameter.DISC_UN_MUTE, + Command = ERDM_Command.DISCOVERY_COMMAND_RESPONSE, + SourceUID = UID, + DestUID = rdmMessage.SourceUID, + ParameterData = new DiscMuteUnmuteResponse().ToPayloadData() + }; + return rdmMessage.DestUID != UID.Broadcast ? response : null; + case ERDM_Parameter.DISC_UNIQUE_BRANCH when rdmMessage.Value is DiscUniqueBranchRequest discUniqueBranchRequest: + if (UID >= discUniqueBranchRequest.StartUid && UID <= discUniqueBranchRequest.EndUid) + { + if (DiscoveryMuted) + return null; response = new RDMMessage { - Parameter = ERDM_Parameter.DISC_UN_MUTE, + Parameter = ERDM_Parameter.DISC_UNIQUE_BRANCH, Command = ERDM_Command.DISCOVERY_COMMAND_RESPONSE, SourceUID = UID, DestUID = rdmMessage.SourceUID, - ParameterData = new DiscMuteUnmuteResponse().ToPayloadData() }; - return rdmMessage.DestUID != UID.Broadcast ? response : null; - case ERDM_Parameter.DISC_UNIQUE_BRANCH when rdmMessage.Value is DiscUniqueBranchRequest discUniqueBranchRequest: - if (UID >= discUniqueBranchRequest.StartUid && UID <= discUniqueBranchRequest.EndUid) - { - if (DiscoveryMuted) - return null; - response = new RDMMessage - { - Parameter = ERDM_Parameter.DISC_UNIQUE_BRANCH, - Command = ERDM_Command.DISCOVERY_COMMAND_RESPONSE, - SourceUID = UID, - DestUID = rdmMessage.SourceUID, - }; - return response; - } - return null; - } + return response; + } + return null; } + } + + var module = this.Modules.FirstOrDefault(m => m.IsHandlingParameter(rdmMessage.Parameter, rdmMessage.Command)); + if (module is not null) + { + response = module.HandleRequest(rdmMessage); + if (response != null) + goto FAIL; + } - if (rdmMessage.SubDevice != SubDevice.Broadcast && !(this.SubDevices?.Any(sd => sd.Subdevice == rdmMessage.SubDevice) ?? true)) + if (rdmMessage.SubDevice != SubDevice.Broadcast && !(this.SubDevices?.Any(sd => sd.Subdevice == rdmMessage.SubDevice) ?? true)) + { + response = new RDMMessage(ERDM_NackReason.SUB_DEVICE_OUT_OF_RANGE) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + goto FAIL; + } + if (rdmMessage.Command == ERDM_Command.GET_COMMAND) + { + ERDM_Parameter parameter = rdmMessage.Parameter; + object requestValue = rdmMessage.Value; + byte messageCounter = 0; + if (rdmMessage.SubDevice == SubDevice.Broadcast) // no Response on Broadcast Subdevice, because this can't work on a if there are more then one Device responding on a single line. { - response = new RDMMessage(ERDM_NackReason.SUB_DEVICE_OUT_OF_RANGE) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + response = new RDMMessage(ERDM_NackReason.SUB_DEVICE_OUT_OF_RANGE) { Parameter = parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; goto FAIL; } - if (rdmMessage.Command == ERDM_Command.GET_COMMAND) + if (parameter == ERDM_Parameter.QUEUED_MESSAGE) { - ERDM_Parameter parameter = rdmMessage.Parameter; - object requestValue = rdmMessage.Value; - byte messageCounter = 0; - if (rdmMessage.SubDevice == SubDevice.Broadcast) // no Response on Broadcast Subdevice, because this can't work on a if there are more then one Device responding on a single line. + if (!SupportQueued) + goto FAIL; + + ERDM_Status statusCode = ERDM_Status.NONE; + if (requestValue is ERDM_Status status) + statusCode = status; + + if (statusCode == ERDM_Status.NONE) + { + response = new RDMMessage(ERDM_NackReason.FORMAT_ERROR) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + goto FAIL; + } + else if (statusCode == ERDM_Status.GET_LAST_MESSAGE) + { + response = controllerCache.GetLastSendQueuedOrStatusRDMMessageResponse(); + if (response != null) + goto FAIL; + + response = new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + goto FAIL; + } + + if (controllerCache.ParameterUpdatedBag.IsEmpty) { - response = new RDMMessage(ERDM_NackReason.SUB_DEVICE_OUT_OF_RANGE) { Parameter = parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + response = new RDMMessage + { + Parameter = ERDM_Parameter.STATUS_MESSAGES, + Command = ERDM_Command.GET_COMMAND_RESPONSE, + ControllerFlags_or_MessageCounter = 0 + }; + if (statusMessageModule is not null) + fillRDMMessageWithStatusMessageData(controllerCache, statusCode, ref response); + goto FAIL; } - if (parameter == ERDM_Parameter.QUEUED_MESSAGE) + else if (controllerCache.ParameterUpdatedBag.TryDequeue(out var item)) { - if (!SupportQueued) - goto FAIL; - - ERDM_Status statusCode = ERDM_Status.NONE; - if (requestValue is ERDM_Status status) - statusCode = status; - - if (statusCode == ERDM_Status.NONE) - { - response = new RDMMessage(ERDM_NackReason.FORMAT_ERROR) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; - goto FAIL; - } - else if (statusCode == ERDM_Status.GET_LAST_MESSAGE) + parameter = item.Parameter; + requestValue = item.Index; + messageCounter = (byte)Math.Min(controllerCache.ParameterUpdatedBag.Count, byte.MaxValue); + } + } + if (parameter == ERDM_Parameter.STATUS_MESSAGES) + { + ERDM_Status statusCode = ERDM_Status.NONE; + if (requestValue is ERDM_Status status) + statusCode = status; + if (statusMessageModule is not null) + { + if (statusCode == ERDM_Status.GET_LAST_MESSAGE) { response = controllerCache.GetLastSendQueuedOrStatusRDMMessageResponse(); if (response != null) @@ -836,522 +541,451 @@ protected RDMMessage processRequestMessage(RDMMessage rdmMessage) response = new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; goto FAIL; } - - if (controllerCache.ParameterUpdatedBag.IsEmpty) + else { response = new RDMMessage { Parameter = ERDM_Parameter.STATUS_MESSAGES, Command = ERDM_Command.GET_COMMAND_RESPONSE, - MessageCounter = 0 + ControllerFlags_or_MessageCounter = 0 }; - if (SupportStatus) - fillRDMMessageWithStatusMessageData(controllerCache, statusCode, ref response); + fillRDMMessageWithStatusMessageData(controllerCache, statusCode, ref response); + controllerCache.SetLastSendQueuedOrStatusRDMMessageResponse(response); + controllerCache.SetLastSendRDMMessageResponse(response); goto FAIL; } - else if (controllerCache.ParameterUpdatedBag.TryDequeue(out var item)) - { - parameter = item.Parameter; - requestValue = item.Index; - messageCounter = (byte)Math.Min(controllerCache.ParameterUpdatedBag.Count, byte.MaxValue); - } - } - if(parameter == ERDM_Parameter.STATUS_MESSAGES) - { - ERDM_Status statusCode = ERDM_Status.NONE; - if (requestValue is ERDM_Status status) - statusCode = status; - if (SupportStatus) - { - if (statusCode == ERDM_Status.GET_LAST_MESSAGE) - { - response = controllerCache.GetLastSendQueuedOrStatusRDMMessageResponse(); - if (response != null) - goto FAIL; - - response = new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; - goto FAIL; - } - else - { - response = new RDMMessage - { - Parameter = ERDM_Parameter.STATUS_MESSAGES, - Command = ERDM_Command.GET_COMMAND_RESPONSE, - MessageCounter = 0 - }; - - fillRDMMessageWithStatusMessageData(controllerCache, statusCode, ref response); - controllerCache.SetLastSendQueuedOrStatusRDMMessageResponse(response); - controllerCache.SetLastSendRDMMessageResponse(response); - goto FAIL; - } - } - else goto FAIL; } - else - removeParameterFromParameterUpdateBag(parameter); + else goto FAIL; + } + else + removeParameterFromParameterUpdateBag(parameter); - parameterValues.TryGetValue(parameter, out object responseValue); + parameterValues.TryGetValue(parameter, out object responseValue); - if(responseValue is ConcurrentDictionary dict) - { - var val = dict[requestValue]; - if (val == null) - throw new ArgumentOutOfRangeException("No matching id found"); - } + if (responseValue is ConcurrentDictionary dict) + { + var val = dict[requestValue]; + if (val == null) + throw new ArgumentOutOfRangeException("No matching id found"); + } - var parameterBag = new ParameterBag(parameter, UID.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); - var define = MetadataFactory.GetDefine(parameterBag); - if (define.GetRequest is null) + var parameterBag = new ParameterBag(parameter, UID.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); + var define = MetadataFactory.GetDefine(parameterBag); + if (define.GetRequest is null) + { + response = new RDMMessage(ERDM_NackReason.UNSUPPORTED_COMMAND_CLASS) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + goto FAIL; + } + //response = this.Modules.FirstOrDefault(m=>m.IsHandlingParameter(parameter))?.HandleRequest(rdmMessage); + if (overflowCacheBags.TryGetValue(rdmMessage.SourceUID, out OverflowCacheBag overflowCache)) + { + if (!overflowCache.Timeouted && overflowCache.Cache.TryDequeue(out byte[] data)) { - response = new RDMMessage(ERDM_NackReason.UNSUPPORTED_COMMAND_CLASS) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + response = new RDMMessage + { + Parameter = parameter, + Command = ERDM_Command.GET_COMMAND_RESPONSE, + ControllerFlags_or_MessageCounter = messageCounter, + ParameterData = data, + }; + if (!overflowCache.Cache.TryPeek(out _)) + overflowCacheBags.Remove(rdmMessage.SourceUID, out _); + else + response.PortID_or_Responsetype = (byte)ERDM_ResponseType.ACK_OVERFLOW; goto FAIL; } - if(overflowCacheBags.TryGetValue(rdmMessage.SourceUID, out OverflowCacheBag overflowCache)) + } + var dataTreeBranch = DataTreeBranch.FromObject(responseValue, requestValue, parameterBag, ERDM_Command.GET_COMMAND_RESPONSE); + try + { + if (!dataTreeBranch.IsUnset) { - if (!overflowCache.Timeouted && overflowCache.Cache.TryDequeue(out byte[] data)) + var data = MetadataFactory.GetResponseMessageData(parameterBag, dataTreeBranch); + if (data != null) { + byte[] pData = null; + if (data.Count() != 1) + { + overflowCacheBags.AddOrUpdate(rdmMessage.SourceUID, (uid) => new OverflowCacheBag(rdmMessage.Parameter, data.ToList()), (uid, o) => new OverflowCacheBag(rdmMessage.Parameter, data.ToList())); + overflowCacheBags[rdmMessage.SourceUID].Cache.TryDequeue(out pData); + } response = new RDMMessage { Parameter = parameter, Command = ERDM_Command.GET_COMMAND_RESPONSE, - MessageCounter = messageCounter, - ParameterData = data, + ControllerFlags_or_MessageCounter = messageCounter, + ParameterData = pData ?? data.FirstOrDefault() ?? new byte[0], + PortID_or_Responsetype = pData is null ? (byte)ERDM_ResponseType.ACK : (byte)ERDM_ResponseType.ACK_OVERFLOW }; - if (!overflowCache.Cache.TryPeek(out _)) - overflowCacheBags.Remove(rdmMessage.SourceUID, out _); - else - response.PortID_or_Responsetype = (byte)ERDM_ResponseType.ACK_OVERFLOW; - goto FAIL; - } - } - var dataTreeBranch = DataTreeBranch.FromObject(responseValue, requestValue, parameterBag, ERDM_Command.GET_COMMAND_RESPONSE); - try - { - if (!dataTreeBranch.IsUnset) - { - var data = MetadataFactory.GetResponseMessageData(parameterBag, dataTreeBranch); - if (data != null) - { - byte[] pData = null; - if (data.Count() !=1) - { - overflowCacheBags.AddOrUpdate(rdmMessage.SourceUID, (uid) => new OverflowCacheBag(rdmMessage.Parameter, data.ToList()), (uid, o) => new OverflowCacheBag(rdmMessage.Parameter, data.ToList())); - pData = overflowCacheBags[rdmMessage.SourceUID].Cache.Dequeue(); - } - response = new RDMMessage - { - Parameter = parameter, - Command = ERDM_Command.GET_COMMAND_RESPONSE, - MessageCounter = messageCounter, - ParameterData = pData ?? data.First(), - PortID_or_Responsetype = pData is null ? (byte)ERDM_ResponseType.ACK : (byte)ERDM_ResponseType.ACK_OVERFLOW - }; - } - if (rdmMessage.Parameter == ERDM_Parameter.QUEUED_MESSAGE) - controllerCache.SetLastSendQueuedOrStatusRDMMessageResponse(response); - controllerCache.SetLastSendRDMMessageResponse(response); } - else - goto FAIL; + if (rdmMessage.Parameter == ERDM_Parameter.QUEUED_MESSAGE) + controllerCache.SetLastSendQueuedOrStatusRDMMessageResponse(response); + controllerCache.SetLastSendRDMMessageResponse(response); } - catch (Exception e) - { - Logger?.LogError(e, $"ParameterBag:{parameterBag}{Environment.NewLine}Command: {rdmMessage.Command}{Environment.NewLine}RequestValue: {requestValue ?? ""}{Environment.NewLine}ResponseValue: {responseValue ?? ""}"); + else goto FAIL; - } } - else if (rdmMessage.Command == ERDM_Command.SET_COMMAND) + catch (Exception e) + { + Logger?.LogError(e, $"ParameterBag:{parameterBag}{Environment.NewLine}Command: {rdmMessage.Command}{Environment.NewLine}RequestValue: {requestValue ?? ""}{Environment.NewLine}ResponseValue: {responseValue ?? ""}"); + goto FAIL; + } + } + else if (rdmMessage.Command == ERDM_Command.SET_COMMAND) + { + bool success = false; + //Handle set Request + if (parameterValues.TryGetValue(rdmMessage.Parameter, out object comparisonValue)) { - bool success = false; - //Handle set Request - if (parameterValues.TryGetValue(rdmMessage.Parameter, out object comparisonValue)) + parameterValues.AddOrUpdate(rdmMessage.Parameter, (_) => { - parameterValues.AddOrUpdate(rdmMessage.Parameter, (_) => rdmMessage.Value, (_,_) => rdmMessage.Value); - success = true; - object responseValue = rdmMessage.Value; - if (comparisonValue is ConcurrentDictionary dict) + try { - switch (rdmMessage.Parameter) - { - case ERDM_Parameter.SENSOR_VALUE: - if (!object.Equals(rdmMessage.Value, byte.MaxValue)) - { - this.Sensors[(byte)rdmMessage.Value].ResetValues(); - responseValue = dict[rdmMessage.Value]; - } - else //Broadcast - { - foreach (var sensor in this.Sensors.Values) - sensor.ResetValues(); - responseValue = new RDMSensorValue(0xff); - } - break; - default: - responseValue = dict[rdmMessage.Value]; - break; - } + return rdmMessage.Value; } - + finally + { + InvokeParameterValueAdded(new ParameterValueAddedEventArgs(rdmMessage.Parameter, rdmMessage.Value)); + } + }, (_, old) => + { try { - updateParameterFromRemote(rdmMessage.Parameter, responseValue); - var parameterBag = new ParameterBag(rdmMessage.Parameter, UID.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); - var dataTreeBranch = DataTreeBranch.FromObject(responseValue, rdmMessage.Value, parameterBag, ERDM_Command.SET_COMMAND_RESPONSE); - if (!dataTreeBranch.IsUnset) - { - var data = MetadataFactory.SetResponseMessageData(parameterBag, dataTreeBranch); - if (data != null) - response = new RDMMessage - { - Parameter = rdmMessage.Parameter, - Command = ERDM_Command.SET_COMMAND_RESPONSE, - ParameterData = data.First(), - }; - } - else - goto FAIL; + return rdmMessage.Value; } - catch (Exception e) + finally { - Logger?.LogError(e); - if (e is ArgumentOutOfRangeException || e is KeyNotFoundException) - response = new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; - else - response = new RDMMessage(ERDM_NackReason.FORMAT_ERROR) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; - - goto FAIL; + InvokeParameterValueChanged(new ParameterValueChangedEventArgs(rdmMessage.Parameter, rdmMessage.Value, old)); } - } - else if (Parameters.Contains(rdmMessage.Parameter))//Parameter is not in parameterValues + }); + success = true; + object responseValue = rdmMessage.Value; + if (comparisonValue is ConcurrentDictionary dict) { - var parameterBag = new ParameterBag(rdmMessage.Parameter, UID.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); - var define = MetadataFactory.GetDefine(parameterBag); switch (rdmMessage.Parameter) { - case ERDM_Parameter.RECORD_SENSORS when rdmMessage.Value is byte sensorID: - success = true; - if (sensorID == 0xFF)//Broadcast - foreach (var sensor in Sensors.Values) - sensor.RecordValue(); - else - Sensors[sensorID].RecordValue(); - response = new RDMMessage + case ERDM_Parameter.SENSOR_VALUE: + if (!object.Equals(rdmMessage.Value, byte.MaxValue)) { - Parameter = rdmMessage.Parameter, - Command = ERDM_Command.SET_COMMAND_RESPONSE - }; - goto FAIL; - case ERDM_Parameter.CLEAR_STATUS_ID: - this.statusMessages.Clear(); - setParameterValue(ERDM_Parameter.STATUS_MESSAGES, this.statusMessages.Select(sm => sm.Value).ToArray()); + this.Sensors[(byte)rdmMessage.Value].ResetValues(); + responseValue = dict[rdmMessage.Value]; + } + else //Broadcast + { + foreach (var sensor in this.Sensors.Values) + sensor.ResetValues(); + responseValue = new RDMSensorValue(0xff); + } + break; + default: + responseValue = dict[rdmMessage.Value]; + break; + } + } + + try + { + var parameterBag = new ParameterBag(rdmMessage.Parameter, UID.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); + var dataTreeBranch = DataTreeBranch.FromObject(responseValue, rdmMessage.Value, parameterBag, ERDM_Command.SET_COMMAND_RESPONSE); + if (!dataTreeBranch.IsUnset) + { + var data = MetadataFactory.SetResponseMessageData(parameterBag, dataTreeBranch); + if (data != null) response = new RDMMessage { Parameter = rdmMessage.Parameter, - Command = ERDM_Command.SET_COMMAND_RESPONSE + Command = ERDM_Command.SET_COMMAND_RESPONSE, + ParameterData = data.First(), }; - goto FAIL; - - default: - response = new RDMMessage(ERDM_NackReason.ACTION_NOT_SUPPORTED) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; - goto FAIL; } + else + goto FAIL; } - else - goto FAIL; - - //Do set Response - if (!success) + catch (Exception e) { - response = new RDMMessage(ERDM_NackReason.FORMAT_ERROR) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + Logger?.LogError(e); + if (e is ArgumentOutOfRangeException || e is KeyNotFoundException) + response = new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + else + response = new RDMMessage(ERDM_NackReason.FORMAT_ERROR) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + goto FAIL; } } - } - catch (Exception e) - { - Logger?.LogError(e, string.Empty); - - if (e is ArgumentOutOfRangeException || e is KeyNotFoundException) - response = new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; - else + else if (Parameters.Contains(rdmMessage.Parameter))//Parameter is not in parameterValues { - var define = MetadataFactory.GetDefine(new ParameterBag(rdmMessage.Parameter, (ushort)ManufacturerID, DeviceModelID, SoftwareVersionID)); - if ( - (rdmMessage.Command == ERDM_Command.GET_COMMAND && !define.GetRequest.HasValue) || - (rdmMessage.Command == ERDM_Command.SET_COMMAND && !define.SetRequest.HasValue)) - response = new RDMMessage(ERDM_NackReason.UNSUPPORTED_COMMAND_CLASS) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; - else - response = new RDMMessage(ERDM_NackReason.ACTION_NOT_SUPPORTED) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + var parameterBag = new ParameterBag(rdmMessage.Parameter, UID.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); + var define = MetadataFactory.GetDefine(parameterBag); + switch (rdmMessage.Parameter) + { + //case ERDM_Parameter.RECORD_SENSORS when rdmMessage.Value is byte sensorID: + // success = true; + // if (sensorID == 0xFF)//Broadcast + // foreach (var sensor in Sensors.Values) + // sensor.RecordValue(); + // else + // Sensors[sensorID].RecordValue(); + // response = new RDMMessage + // { + // Parameter = rdmMessage.Parameter, + // Command = ERDM_Command.SET_COMMAND_RESPONSE + // }; + // goto FAIL; + //case ERDM_Parameter.CLEAR_STATUS_ID: + // this.statusMessages.Clear(); + // setParameterValue(ERDM_Parameter.STATUS_MESSAGES, this.statusMessages.Select(sm => sm.Value).ToArray()); + // response = new RDMMessage + // { + // Parameter = rdmMessage.Parameter, + // Command = ERDM_Command.SET_COMMAND_RESPONSE + // }; + // goto FAIL; + + default: + response = new RDMMessage(ERDM_NackReason.FORMAT_ERROR) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + goto FAIL; + } } - goto FAIL; - } - FAIL: - if (rdmMessage.SubDevice == SubDevice.Broadcast) // no Response on Broadcast Subdevice, because this can't work on a if there are more then one Device responding on a singel line. - return null; - if (rdmMessage.DestUID.IsBroadcast) // no Response on Broadcast - return null; - if(response == null) - { + else + goto FAIL; + //Do set Response + if (!success) + { + response = new RDMMessage(ERDM_NackReason.FORMAT_ERROR) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + goto FAIL; + } } + } + catch (Exception e) + { + Logger?.LogError(e, string.Empty); - response ??= new RDMMessage(ERDM_NackReason.UNKNOWN_PID) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; - - response.TransactionCounter = rdmMessage.TransactionCounter; - response.SourceUID = rdmMessage.DestUID; - response.DestUID = rdmMessage.SourceUID; - response.SubDevice = rdmMessage.SubDevice; - if(response.ResponseType == ERDM_ResponseType.NACK_REASON) + if (e is ArgumentOutOfRangeException || e is KeyNotFoundException) + response = new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + else { - Logger?.LogTrace($"RDM NACK: {response.NackReason} for Parameter: {response.Parameter} on Device: {this.UID} with Subdevice: {response.SubDevice}"); + var define = MetadataFactory.GetDefine(new ParameterBag(rdmMessage.Parameter, (ushort)ManufacturerID, DeviceModelID, SoftwareVersionID)); + if ( + (rdmMessage.Command == ERDM_Command.GET_COMMAND && !define.GetRequest.HasValue) || + (rdmMessage.Command == ERDM_Command.SET_COMMAND && !define.SetRequest.HasValue)) + response = new RDMMessage(ERDM_NackReason.UNSUPPORTED_COMMAND_CLASS) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + else + response = new RDMMessage(ERDM_NackReason.FORMAT_ERROR) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; } - return response; + goto FAIL; } - public sealed override IReadOnlyDictionary GetAllParameterValues() + FAIL: + if (rdmMessage.SubDevice == SubDevice.Broadcast) // no Response on Broadcast Subdevice, because this can't work on a if there are more then one Device responding on a singel line. + return null; + if (rdmMessage.DestUID.IsBroadcast) // no Response on Broadcast + return null; + if (response == null) { - return base.GetAllParameterValues(); + } - private void updateParameterFromRemote(ERDM_Parameter parameter, object value) + response ??= new RDMMessage(ERDM_NackReason.UNKNOWN_PID) { Parameter = rdmMessage.Parameter, Command = rdmMessage.Command | ERDM_Command.RESPONSE }; + + response.TransactionCounter = rdmMessage.TransactionCounter; + response.SourceUID = rdmMessage.DestUID; + response.DestUID = rdmMessage.SourceUID; + response.SubDevice = rdmMessage.SubDevice; + if (response.ResponseType == ERDM_ResponseType.NACK_REASON) { - switch (parameter) - { - case ERDM_Parameter.DMX_START_ADDRESS: - DMXAddress = (ushort)value; - break; - case ERDM_Parameter.DMX_PERSONALITY: - CurrentPersonality = (byte)value; - break; - case ERDM_Parameter.DEVICE_LABEL: - DeviceLabel = (string)value; - break; - case ERDM_Parameter.IDENTIFY_DEVICE: - Identify = (bool)value; - break; - } + Logger?.LogTrace($"RDM NACK: {response.NackReason} for Parameter: {response.Parameter} on Device: {this.UID} with Subdevice: {response.SubDevice}"); } - private void updateParameterBag(ERDM_Parameter parameter, object index = null) + return response; + } + public sealed override IReadOnlyDictionary GetAllParameterValues() + { + return base.GetAllParameterValues(); + } + + private void updateParameterBag(ERDM_Parameter parameter, object index = null) + { + if (!IsInitialized || !_initialized) + return; + try { - if (!IsInitialized || !_initialized) - return; - try - { - addOrUpdateParameterFromParameterUpdateBag(parameter, index); - } - catch(Exception e) - { - Logger?.LogError(e); - } + addOrUpdateParameterFromParameterUpdateBag(parameter, index); + } + catch (Exception e) + { + Logger?.LogError(e); } - private void addOrUpdateParameterFromParameterUpdateBag(ERDM_Parameter parameter, object index = null) + } + private void addOrUpdateParameterFromParameterUpdateBag(ERDM_Parameter parameter, object index = null) + { + foreach (var cache in controllerCommunicationCache) { - foreach (var cache in controllerCommunicationCache) + if (cache.Value.ParameterUpdatedBag.Any(p => p.Parameter == parameter)) { - if (cache.Value.ParameterUpdatedBag.Any(p => p.Parameter == parameter)) - { - var tempQueue = new ConcurrentQueue(); - while (cache.Value.ParameterUpdatedBag.TryDequeue(out var item)) - if (!(item.Parameter.Equals(parameter) && Equals(item.Index, index))) - tempQueue.Enqueue(item); + var tempQueue = new ConcurrentQueue(); + while (cache.Value.ParameterUpdatedBag.TryDequeue(out var item)) + if (!(item.Parameter.Equals(parameter) && Equals(item.Index, index))) + tempQueue.Enqueue(item); - while (tempQueue.TryDequeue(out var item)) - cache.Value.ParameterUpdatedBag.Enqueue(item); - } - cache.Value.ParameterUpdatedBag.Enqueue(new ParameterUpdatedBag(parameter, index)); + while (tempQueue.TryDequeue(out var item)) + cache.Value.ParameterUpdatedBag.Enqueue(item); } + cache.Value.ParameterUpdatedBag.Enqueue(new ParameterUpdatedBag(parameter, index)); } - private void removeParameterFromParameterUpdateBag(ERDM_Parameter parameter, object index = null) + } + private void removeParameterFromParameterUpdateBag(ERDM_Parameter parameter, object index = null) + { + foreach (var cache in controllerCommunicationCache) { - foreach (var cache in controllerCommunicationCache) + if (cache.Value.ParameterUpdatedBag.Any(p => p.Parameter == parameter && p.Index == index)) { - if (cache.Value.ParameterUpdatedBag.Any(p => p.Parameter == parameter && p.Index == index)) - { - var tempQueue = new ConcurrentQueue(); - while (cache.Value.ParameterUpdatedBag.TryDequeue(out var item)) - if (!(item.Parameter.Equals(parameter) && Equals(item.Index, index))) - tempQueue.Enqueue(item); + var tempQueue = new ConcurrentQueue(); + while (cache.Value.ParameterUpdatedBag.TryDequeue(out var item)) + if (!(item.Parameter.Equals(parameter) && Equals(item.Index, index))) + tempQueue.Enqueue(item); - while (tempQueue.TryDequeue(out var item)) - cache.Value.ParameterUpdatedBag.Enqueue(item); - } + while (tempQueue.TryDequeue(out var item)) + cache.Value.ParameterUpdatedBag.Enqueue(item); } } + } - protected void AddStatusMessage(RDMStatusMessage statusMessage) - { - if (!SupportStatus) - throw new NotSupportedException($"The Device {this.UID} not support Status Messages."); - - int id = 0; - if (this.statusMessages.Count != 0) - id = this.statusMessages.Max(s => s.Key) + 1; - if (this.statusMessages.TryAdd(id, statusMessage)) - setParameterValue(ERDM_Parameter.STATUS_MESSAGES, this.statusMessages.Select(sm => sm.Value).ToArray()); - } - protected void ClearStatusMessage(RDMStatusMessage statusMessage) + private void fillRDMMessageWithStatusMessageData(ControllerCommunicationCache controllerCache, ERDM_Status statusCode, ref RDMMessage rdmMessage) + { + var lastSendStatusMessageID = controllerCache.GetLastSendStatusMessageID(statusCode); + var _messages = StatusMessages.Where(s => s.Key > lastSendStatusMessageID && matchStausCode(statusCode, s.Value)).OrderBy(s => s.Key).ToList(); + if (_messages.Count() != 0) { - if (!SupportStatus) - throw new NotSupportedException($"The Device {this.UID} not support Status Messages."); - this.statusMessages.Where(s => s.Value.Equals(statusMessage)).ToList().ForEach(s => + byte count = 0; + List data = new List(); + Dictionary parsedMessages = new Dictionary(); + while (count < 25 && _messages.Count != 0) { - s.Value.Clear(); - }); - setParameterValue(ERDM_Parameter.STATUS_MESSAGES, this.statusMessages.Select(sm => sm.Value).ToArray()); - } - protected void RemoveStatusMessage(RDMStatusMessage statusMessage) - { - if (!SupportStatus) - throw new NotSupportedException($"The Device {this.UID} not support Status Messages."); - - bool succes = false; - this.statusMessages.Where(s => s.Value.Equals(statusMessage)).ToList().ForEach(s => + var pair = _messages.First(); + parsedMessages.Add(pair.Key, pair.Value); + data.AddRange(pair.Value.ToPayloadData()); + _messages.RemoveAt(0); + count++; + } + if (parsedMessages.Count != 0) { - if (this.statusMessages.TryRemove(s.Key, out _)) - succes = true; - }); - if(succes) - setParameterValue(ERDM_Parameter.STATUS_MESSAGES, this.statusMessages.Select(sm => sm.Value).ToArray()); + controllerCache.SetLastSendStatusMessageID(statusCode, _messages.Count == 0 ? -1 : parsedMessages.Max(s => s.Key)); + if (_messages.Count != 0) + rdmMessage.PortID_or_Responsetype = (byte)ERDM_ResponseType.ACK_OVERFLOW; + rdmMessage.ParameterData = data.ToArray(); + } } - private void fillRDMMessageWithStatusMessageData(ControllerCommunicationCache controllerCache, ERDM_Status statusCode, ref RDMMessage rdmMessage) + bool matchStausCode(ERDM_Status statusCode, RDMStatusMessage statusMessage) { - var lastSendStatusMessageID= controllerCache.GetLastSendStatusMessageID(statusCode); - var _messages = statusMessages.Where(s => s.Key > lastSendStatusMessageID && matchStausCode(statusCode, s.Value)).OrderBy(s => s.Key).ToList(); - if (_messages.Count() != 0) - { - byte count = 0; - List data = new List(); - Dictionary parsedMessages = new Dictionary(); - while (count < 25 && _messages.Count != 0) - { - var pair = _messages.First(); - parsedMessages.Add(pair.Key, pair.Value); - data.AddRange(pair.Value.ToPayloadData()); - _messages.RemoveAt(0); - count++; - } - if (parsedMessages.Count != 0) - { - controllerCache.SetLastSendStatusMessageID(statusCode, _messages.Count == 0 ? -1 : parsedMessages.Max(s => s.Key)); - if (_messages.Count != 0) - rdmMessage.PortID_or_Responsetype = (byte)ERDM_ResponseType.ACK_OVERFLOW; - rdmMessage.ParameterData = data.ToArray(); - } - } - bool matchStausCode(ERDM_Status statusCode, RDMStatusMessage statusMessage) - { - if (statusCode == ERDM_Status.GET_LAST_MESSAGE) - throw new NotSupportedException($"The StatusCode: {statusCode}, not supported in this Method."); + if (statusCode == ERDM_Status.GET_LAST_MESSAGE) + throw new NotSupportedException($"The StatusCode: {statusCode}, not supported in this Method."); - if (statusMessage.EStatusType == ERDM_Status.GET_LAST_MESSAGE) - throw new NotSupportedException($"The StatusCode: {statusMessage.EStatusType}, not supported in this Method."); + if (statusMessage.EStatusType == ERDM_Status.GET_LAST_MESSAGE) + throw new NotSupportedException($"The StatusCode: {statusMessage.EStatusType}, not supported in this Method."); - var statusType = statusMessage.EStatusType & ~ERDM_Status.CLEARED; + var statusType = statusMessage.EStatusType & ~ERDM_Status.CLEARED; - return statusType >= statusCode; - } + return statusType >= statusCode; } - private ControllerCommunicationCache getControllerCommunicationCache(UID uid) + } + private ControllerCommunicationCache getControllerCommunicationCache(UID uid) + { + if (!controllerCommunicationCache.TryGetValue(uid, out var cache)) { - if (!controllerCommunicationCache.TryGetValue(uid, out var cache)) - { - cache = new ControllerCommunicationCache(uid); - controllerCommunicationCache.TryAdd(uid, cache); - } - return cache; + cache = new ControllerCommunicationCache(uid); + controllerCommunicationCache.TryAdd(uid, cache); } - protected sealed override void OnDispose() + return cache; + } + protected sealed override void OnDispose() + { + RDMSharp.Instance.RequestReceivedEvent -= Instance_RequestReceivedEvent; + try { - RDMSharp.Instance.RequestReceivedEvent -= Instance_RequestReceivedEvent; - try - { - onDispose(); - } - catch (Exception e) - { - Logger?.LogError(e); - } + onDispose(); } - protected abstract void onDispose(); - - private class OverflowCacheBag + catch (Exception e) { - public readonly ERDM_Parameter Parameter; - public readonly DateTime CreationTime; - public readonly Queue Cache = new Queue(); + Logger?.LogError(e); + } + } + protected abstract void onDispose(); - public bool Timeouted - { - get - { - return (DateTime.UtcNow - CreationTime).TotalSeconds > 5; - } - } + private class OverflowCacheBag + { + public readonly ERDM_Parameter Parameter; + public readonly DateTime CreationTime; + public readonly Queue Cache = new Queue(); - public OverflowCacheBag(ERDM_Parameter parameter, IReadOnlyCollection cache) + public bool Timeouted + { + get { - Parameter = parameter; - CreationTime = DateTime.UtcNow; - foreach (var c in cache) - Cache.Enqueue(c); + return (DateTime.UtcNow - CreationTime).TotalSeconds > 5; } } - private class ControllerCommunicationCache + public OverflowCacheBag(ERDM_Parameter parameter, IReadOnlyCollection cache) { - public readonly UID Uid; - public DateTime LastSeen = DateTime.UtcNow; - private ConcurrentDictionary lastSendStatusMessageID; - private RDMMessage lastSendQueuedOrStatusRDMMessageResponse; - private RDMMessage lastSendRDMMessageResponse; + Parameter = parameter; + CreationTime = DateTime.UtcNow; + foreach (var c in cache) + Cache.Enqueue(c); + } + } + + private class ControllerCommunicationCache + { + public readonly UID Uid; + public DateTime LastSeen = DateTime.UtcNow; + private ConcurrentDictionary lastSendStatusMessageID; + private RDMMessage lastSendQueuedOrStatusRDMMessageResponse; + private RDMMessage lastSendRDMMessageResponse; - internal ConcurrentQueue ParameterUpdatedBag = new ConcurrentQueue(); + internal ConcurrentQueue ParameterUpdatedBag = new ConcurrentQueue(); - public ControllerCommunicationCache(UID uid) - { - this.Uid = uid; - } - public void Seen() - { - LastSeen = DateTime.UtcNow; - } + public ControllerCommunicationCache(UID uid) + { + this.Uid = uid; + } + public void Seen() + { + LastSeen = DateTime.UtcNow; + } - public int GetLastSendStatusMessageID(ERDM_Status statusCode) - { - if (lastSendStatusMessageID?.TryGetValue(statusCode, out int id) ?? false) - return id; + public int GetLastSendStatusMessageID(ERDM_Status statusCode) + { + if (lastSendStatusMessageID?.TryGetValue(statusCode, out int id) ?? false) + return id; - return -1; - } + return -1; + } - public void SetLastSendStatusMessageID(ERDM_Status statusCode, int id) - { - if(lastSendStatusMessageID==null) - lastSendStatusMessageID = new ConcurrentDictionary(); + public void SetLastSendStatusMessageID(ERDM_Status statusCode, int id) + { + if (lastSendStatusMessageID == null) + lastSendStatusMessageID = new ConcurrentDictionary(); - lastSendStatusMessageID.AddOrUpdate(statusCode, id, (o, p) => id); - } - public void SetLastSendQueuedOrStatusRDMMessageResponse(RDMMessage rdmMessage) - { - lastSendQueuedOrStatusRDMMessageResponse = rdmMessage; - } - public RDMMessage GetLastSendQueuedOrStatusRDMMessageResponse() - { - return lastSendQueuedOrStatusRDMMessageResponse; - } - public void SetLastSendRDMMessageResponse(RDMMessage rdmMessage) - { - lastSendRDMMessageResponse = rdmMessage; - } - public RDMMessage GetLastSendRDMMessageResponse() - { - return lastSendRDMMessageResponse; - } + lastSendStatusMessageID.AddOrUpdate(statusCode, id, (o, p) => id); + } + public void SetLastSendQueuedOrStatusRDMMessageResponse(RDMMessage rdmMessage) + { + lastSendQueuedOrStatusRDMMessageResponse = rdmMessage; + } + public RDMMessage GetLastSendQueuedOrStatusRDMMessageResponse() + { + return lastSendQueuedOrStatusRDMMessageResponse; + } + public void SetLastSendRDMMessageResponse(RDMMessage rdmMessage) + { + lastSendRDMMessageResponse = rdmMessage; + } + public RDMMessage GetLastSendRDMMessageResponse() + { + return lastSendRDMMessageResponse; } } } \ No newline at end of file diff --git a/RDMSharp/RDM/Device/AbstractRDMCache.cs b/RDMSharp/RDM/Device/AbstractRDMCache.cs index cbca016..7d565ff 100644 --- a/RDMSharp/RDM/Device/AbstractRDMCache.cs +++ b/RDMSharp/RDM/Device/AbstractRDMCache.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using RDMSharp.Metadata; +using RDMSharp.RDM.Device; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -8,380 +9,409 @@ using System.Threading.Tasks; using static RDMSharp.PeerToPeerProcess; -namespace RDMSharp +namespace RDMSharp; + +public abstract class AbstractRDMCache : IDisposable { - public abstract class AbstractRDMCache : IDisposable + protected static ILogger Logger = Logging.CreateLogger(); + protected bool IsDisposed { get; private set; } + protected bool IsDisposing { get; private set; } + internal 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(); } + } + internal protected event EventHandler ParameterValueAdded; + internal protected event EventHandler ParameterValueChanged; + protected event EventHandler ParameterRequested; + protected ConcurrentDictionary parameterMetadataBag { get; private set; } = new ConcurrentDictionary(); + public virtual IReadOnlyDictionary ParameterMetadataBag + { + get { return this.parameterMetadataBag?.AsReadOnly(); } + } + internal protected event EventHandler ParameterMetadataAdded; + + public class ParameterValueAddedEventArgs : EventArgs { - protected static ILogger Logger = Logging.CreateLogger(); - protected bool IsDisposed { get; private set; } - protected bool IsDisposing { get; private set; } - internal ConcurrentDictionary parameterValuesDataTreeBranch { get; private set; } = new ConcurrentDictionary(); - protected ConcurrentDictionary parameterValuesDependeciePropertyBag { get; private set; } = new ConcurrentDictionary(); + public readonly ERDM_Parameter Parameter; + public readonly object Index; + public readonly object Value; - protected ConcurrentDictionary parameterValues { get; private set; } = new ConcurrentDictionary(); - public virtual IReadOnlyDictionary ParameterValues + public ParameterValueAddedEventArgs(ERDM_Parameter parameter, object value, object index = null) { - get { return this.parameterValues?.AsReadOnly(); } + Parameter = parameter; + Index = index; + Value = value; } - protected event EventHandler ParameterValueAdded; - protected event EventHandler ParameterValueChanged; - protected event EventHandler ParameterRequested; + } + public class ParameterValueChangedEventArgs : EventArgs + { + public readonly ERDM_Parameter Parameter; + public readonly object Index; + public readonly object NewValue; + public readonly object OldValue; - public class ParameterValueAddedEventArgs : EventArgs + public ParameterValueChangedEventArgs(ERDM_Parameter parameter, object newValue, object oldValue, object index = null) { - public readonly ERDM_Parameter Parameter; - public readonly object Index; - public readonly object Value; - - public ParameterValueAddedEventArgs(ERDM_Parameter parameter, object value, object index = null) - { - Parameter = parameter; - Index = index; - Value = value; - } + Parameter = parameter; + Index = index; + NewValue = newValue; + OldValue = oldValue; } - public class ParameterValueChangedEventArgs : EventArgs - { - public readonly ERDM_Parameter Parameter; - public readonly object Index; - public readonly object NewValue; - public readonly object OldValue; + } + public class ParameterRequestedEventArgs : EventArgs + { + public readonly ERDM_Parameter Parameter; + public readonly object Index; - public ParameterValueChangedEventArgs(ERDM_Parameter parameter, object newValue, object oldValue, object index = null) - { - Parameter = parameter; - Index = index; - NewValue = newValue; - OldValue = oldValue; - } - } - public class ParameterRequestedEventArgs : EventArgs + public ParameterRequestedEventArgs(ERDM_Parameter parameter, object index = null) { - public readonly ERDM_Parameter Parameter; - public readonly object Index; - - public ParameterRequestedEventArgs(ERDM_Parameter parameter, object index = null) - { - Parameter = parameter; - Index = index; - } + Parameter = parameter; + Index = index; } + } - public AbstractRDMCache() - { + public AbstractRDMCache() + { - } + } - protected void InvokeParameterValueAdded(ParameterValueAddedEventArgs e) - { - this.ParameterValueAdded?.InvokeFailSafe(this, e); - } + protected void InvokeParameterValueAdded(ParameterValueAddedEventArgs e) + { + this.ParameterValueAdded?.InvokeFailSafe(this, e); + } + protected void InvokeParameterValueChanged(ParameterValueChangedEventArgs e) + { + this.ParameterValueChanged?.InvokeFailSafe(this, e); + } - protected void updateParameterValuesDependeciePropertyBag(ERDM_Parameter parameter, DataTreeBranch dataTreeBranch) + 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 obj = dataTreeBranch.ParsedObject; - if (obj == null) - return; + 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); - foreach (var p in obj.GetType().GetProperties().Where(p => p.GetCustomAttributes().Any()).ToList()) + object valueToStore = dataTreeBranch.ParsedObject ?? dataTreeBranch; + if (bag.Index == null) + this.parameterValues.AddOrUpdate(bag.Parameter, (o1) => { - object value = p.GetValue(obj); - foreach (var item in p.GetCustomAttributes()) - parameterValuesDependeciePropertyBag.AddOrUpdate(item.Bag, value, (o1, o2) => value); - } - } + try + { + return valueToStore; + } + finally + { + ParameterValueAdded?.InvokeFailSafe(this, new ParameterValueAddedEventArgs(o1, valueToStore)); + } + }, (o1, o2) => + { + try + { + if (o2.GetType() != valueToStore.GetType()) + { + if (o2 is IRDMPayloadObjectOneOf oneOf) + { + oneOf = (IRDMPayloadObjectOneOf)Activator.CreateInstance(oneOf.GetType(), valueToStore, oneOf.Count); + valueToStore = oneOf; + } + } + return valueToStore; + } + finally + { + if (o2 != valueToStore) + ParameterValueChanged?.InvokeFailSafe(this, new ParameterValueChangedEventArgs(o1, valueToStore, o2)); + } + }); - protected void updateParameterValuesDataTreeBranch(ParameterDataCacheBag bag, DataTreeBranch dataTreeBranch) + else { - parameterValuesDataTreeBranch.AddOrUpdate(bag, dataTreeBranch, (o1, o2) => dataTreeBranch); - - object valueToStore = dataTreeBranch.ParsedObject ?? dataTreeBranch; - if (bag.Index == null) - this.parameterValues.AddOrUpdate(bag.Parameter, (o1) => + this.parameterValues.AddOrUpdate(bag.Parameter, + (pid) => + //Add { try { - return valueToStore; + ConcurrentDictionary dict = new ConcurrentDictionary(); + dict.AddOrUpdate(bag.Index, valueToStore, (o1, o2) => valueToStore); + return dict; } finally { - ParameterValueAdded?.InvokeFailSafe(this, new ParameterValueAddedEventArgs(o1, valueToStore)); + ParameterValueAdded?.InvokeFailSafe(this, new ParameterValueAddedEventArgs(pid, valueToStore, bag.Index)); } - }, (o1, o2) => + }, + (pid, cd) => + // Update { + object old = null; + bool changed = false; try { - if(o2.GetType() != valueToStore.GetType()) + ConcurrentDictionary dict = cd as ConcurrentDictionary ?? new ConcurrentDictionary(); + dict.AddOrUpdate(bag.Index, valueToStore, (_, o2) => { - if(o2 is IRDMPayloadObjectOneOf oneOf) - { - oneOf = (IRDMPayloadObjectOneOf)Activator.CreateInstance(oneOf.GetType(), valueToStore, oneOf.Count); - valueToStore = oneOf; - } - } - return valueToStore; + if (o2 == valueToStore) + return valueToStore; + + old = o2; + changed = true; + return valueToStore; + }); + return dict; } - finally + catch (Exception ex) { - if (o2 != valueToStore) - ParameterValueChanged?.InvokeFailSafe(this, new ParameterValueChangedEventArgs(o1, valueToStore, o2)); + Logger?.LogError(ex); + return null; } - }); - - else - { - this.parameterValues.AddOrUpdate(bag.Parameter, - (pid) => - //Add + finally { - try - { - ConcurrentDictionary dict = new ConcurrentDictionary(); - dict.AddOrUpdate(bag.Index, valueToStore, (o1, o2) => valueToStore); - return dict; - } - finally - { + if (changed) + ParameterValueChanged?.InvokeFailSafe(this, new ParameterValueChangedEventArgs(pid, valueToStore, old, bag.Index)); + else ParameterValueAdded?.InvokeFailSafe(this, new ParameterValueAddedEventArgs(pid, valueToStore, bag.Index)); - } - }, - (pid, cd) => - // Update - { - object old = null; - bool changed = false; - try - { - ConcurrentDictionary dict = cd as ConcurrentDictionary ?? new ConcurrentDictionary(); - dict.AddOrUpdate(bag.Index, valueToStore, (_, o2) => - { - if (o2 == valueToStore) - return valueToStore; + } + }); + } - old = o2; - changed = true; - return valueToStore; - }); - return dict; - } - catch(Exception ex) - { - Logger?.LogError(ex); - return null; - } - finally - { - if (changed) - ParameterValueChanged?.InvokeFailSafe(this, new ParameterValueChangedEventArgs(pid, valueToStore, old, bag.Index)); - else - ParameterValueAdded?.InvokeFailSafe(this, new ParameterValueAddedEventArgs(pid, valueToStore, bag.Index)); - } - }); - } + ParameterRequested?.InvokeFailSafe(this, new ParameterRequestedEventArgs(bag.Parameter, bag.Index)); + } + protected virtual async Task OnSendRDMMessage(RDMMessage rdmMessage) + { + await Task.CompletedTask; + } + protected virtual async Task OnResponseMessage(RDMMessage rdmMessage) + { + await Task.CompletedTask; + } - ParameterRequested?.InvokeFailSafe(this, new ParameterRequestedEventArgs(bag.Parameter, bag.Index)); - } - protected virtual async Task OnSendRDMMessage(RDMMessage rdmMessage) - { - await Task.CompletedTask; - } - protected virtual async Task OnResponseMessage(RDMMessage rdmMessage) - { - await Task.CompletedTask; - } + internal protected void tryAddParameterMetadata(ERDM_Parameter pid) + { + if (!parameterMetadataBag.ContainsKey(pid)) + if (parameterMetadataBag.TryAdd(pid, new ParameterMetadata(pid))) + ParameterMetadataAdded?.InvokeFailSafe(this, parameterMetadataBag[pid]); + } + protected async Task runPeerToPeerProcess(PeerToPeerProcess ptpProcess) + { + ptpProcess.BeforeSendMessage = OnSendRDMMessage; + ptpProcess.ResponseMessage = OnResponseMessage; + tryAddParameterMetadata(ptpProcess.ParameterBag.PID); - protected async Task runPeerToPeerProcess(PeerToPeerProcess ptpProcess) + parameterMetadataBag[ptpProcess.ParameterBag.PID].AddPeerToPeerProcess(ptpProcess); + await ptpProcess?.Run(); + } + protected async Task requestSetParameterWithEmptyPayload(ParameterBag parameterBag, MetadataJSONObjectDefine define, UID uid, SubDevice subDevice) + { + PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.SET_COMMAND, uid, subDevice, parameterBag); + await runPeerToPeerProcess(ptpProcess); + if (!ptpProcess.ResponsePayloadObject.IsUnset) { - ptpProcess.BeforeSendMessage = OnSendRDMMessage; - ptpProcess.ResponseMessage = OnResponseMessage; - await ptpProcess?.Run(); + updateParameterValuesDependeciePropertyBag(parameterBag.PID, ptpProcess.ResponsePayloadObject); + updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(parameterBag.PID), ptpProcess.ResponsePayloadObject); + return ptpProcess.State == PeerToPeerProcess.EPeerToPeerProcessState.Finished; } - protected async Task requestSetParameterWithEmptyPayload(ParameterBag parameterBag, MetadataJSONObjectDefine define, UID uid, SubDevice subDevice) + return false; + } + protected async Task requestSetParameterWithPayload(ParameterBag parameterBag, MetadataJSONObjectDefine define, UID uid, SubDevice subDevice, object value) + { + define.GetCommand(Metadata.JSON.Command.ECommandDublicate.SetRequest, out var cmd); + var req = cmd.Value.GetRequiredProperties(); + if (req.Length == 1) { - PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.SET_COMMAND, uid, subDevice, parameterBag); + DataTreeBranch dataTreeBranch = DataTreeBranch.FromObject(value, null, parameterBag, ERDM_Command.SET_COMMAND); + PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.SET_COMMAND, uid, subDevice, parameterBag, dataTreeBranch); await runPeerToPeerProcess(ptpProcess); - if (!ptpProcess.ResponsePayloadObject.IsUnset) - { - updateParameterValuesDependeciePropertyBag(parameterBag.PID, ptpProcess.ResponsePayloadObject); - updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(parameterBag.PID), ptpProcess.ResponsePayloadObject); - return ptpProcess.State == PeerToPeerProcess.EPeerToPeerProcessState.Finished; - } - return false; - } - protected async Task requestSetParameterWithPayload(ParameterBag parameterBag, MetadataJSONObjectDefine define, UID uid, SubDevice subDevice, object value) - { - define.GetCommand(Metadata.JSON.Command.ECommandDublicate.SetRequest, out var cmd); - var req = cmd.Value.GetRequiredProperties(); - if (req.Length == 1) + if (ptpProcess.State == PeerToPeerProcess.EPeerToPeerProcessState.Failed) + throw new Exception($"Failed to set parameter {parameterBag.PID} with value {value}"); + if (ptpProcess.State == PeerToPeerProcess.EPeerToPeerProcessState.Finished) { - DataTreeBranch dataTreeBranch = DataTreeBranch.FromObject(value, null, parameterBag, ERDM_Command.SET_COMMAND); - PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.SET_COMMAND, uid, subDevice, parameterBag, dataTreeBranch); - await runPeerToPeerProcess(ptpProcess); - if (ptpProcess.State == PeerToPeerProcess.EPeerToPeerProcessState.Failed) - throw new Exception($"Failed to set parameter {parameterBag.PID} with value {value}"); - if (ptpProcess.State == PeerToPeerProcess.EPeerToPeerProcessState.Finished) + if (ptpProcess.ResponsePayloadObject.IsEmpty && define.GetResponse.HasValue) { - if (ptpProcess.ResponsePayloadObject.IsEmpty && define.GetResponse.HasValue) + updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ptpProcess.ParameterBag.PID), dataTreeBranch); + if (this.ParameterValues.TryGetValue(parameterBag.PID, out object cacheValue)) { - updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ptpProcess.ParameterBag.PID), dataTreeBranch); - if (this.ParameterValues.TryGetValue(parameterBag.PID, out object cacheValue)) - { - if (value != cacheValue) - throw new Exception($"Failed to set parameter {parameterBag.PID} with value {value}, cache value is {cacheValue}"); - } + if (value != cacheValue) + throw new Exception($"Failed to set parameter {parameterBag.PID} with value {value}, cache value is {cacheValue}"); } - else if (!ptpProcess.ResponsePayloadObject.IsUnset && define.GetResponse.HasValue) - updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ptpProcess.ParameterBag.PID), ptpProcess.ResponsePayloadObject); - return true; } + else if (!ptpProcess.ResponsePayloadObject.IsUnset && define.GetResponse.HasValue) + updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ptpProcess.ParameterBag.PID), ptpProcess.ResponsePayloadObject); + return true; } - return false; } + return false; + } - protected async Task requestGetParameterWithEmptyPayload(ParameterBag parameterBag, MetadataJSONObjectDefine define, UID uid, SubDevice subDevice) + protected async Task requestGetParameterWithEmptyPayload(ParameterBag parameterBag, MetadataJSONObjectDefine define, UID uid, SubDevice subDevice) + { + try { - try - { - PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.GET_COMMAND, uid, subDevice, parameterBag); - await runPeerToPeerProcess(ptpProcess); - if (!ptpProcess.ResponsePayloadObject.IsUnset) - { - updateParameterValuesDependeciePropertyBag(ptpProcess.ParameterBag.PID, ptpProcess.ResponsePayloadObject); - updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ptpProcess.ParameterBag.PID), ptpProcess.ResponsePayloadObject); - } - return ptpProcess.MessageCounter; - } - catch(Exception e) + PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.GET_COMMAND, uid, subDevice, parameterBag); + await runPeerToPeerProcess(ptpProcess); + if (!ptpProcess.ResponsePayloadObject.IsUnset) { - Logger?.LogError(e, $"Failed to get parameter {parameterBag.PID} with empty payload"); + updateParameterValuesDependeciePropertyBag(ptpProcess.ParameterBag.PID, ptpProcess.ResponsePayloadObject); + updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ptpProcess.ParameterBag.PID), ptpProcess.ResponsePayloadObject); } - return 0; + return ptpProcess.MessageCounter; + } + catch (Exception e) + { + Logger?.LogError(e, $"Failed to get parameter {parameterBag.PID} with empty payload"); } - protected async Task requestGetParameterWithPayload(ParameterBag parameterBag, MetadataJSONObjectDefine define, UID uid, SubDevice subDevice, object i=null) + return 0; + } + protected async Task requestGetParameterWithPayload(ParameterBag parameterBag, MetadataJSONObjectDefine define, UID uid, SubDevice subDevice, object i = null) + { + define.GetCommand(Metadata.JSON.Command.ECommandDublicate.GetRequest, out var cmd); + var req = cmd.Value.GetRequiredProperties(); + if (req.Length == 1 && req[0] is Metadata.JSON.OneOfTypes.IIntegerType intType) { - define.GetCommand(Metadata.JSON.Command.ECommandDublicate.GetRequest, out var cmd); - var req = cmd.Value.GetRequiredProperties(); - if (req.Length == 1 && req[0] is Metadata.JSON.OneOfTypes.IIntegerType intType) + try { - try + string name = intType.Name; + var depBag = parameterValuesDependeciePropertyBag.FirstOrDefault(bag => bag.Key.Parameter == parameterBag.PID && bag.Key.Command == Metadata.JSON.Command.ECommandDublicate.GetRequest && string.Equals(bag.Key.Name, name)); + IComparable dependecyValue = (IComparable)depBag.Value; + switch (parameterBag.PID) { - string name = intType.Name; - var depBag = parameterValuesDependeciePropertyBag.FirstOrDefault(bag => bag.Key.Parameter == parameterBag.PID && bag.Key.Command == Metadata.JSON.Command.ECommandDublicate.GetRequest && string.Equals(bag.Key.Name, name)); - IComparable dependecyValue = (IComparable)depBag.Value; + case ERDM_Parameter.STATUS_MESSAGES: + i = (byte)0; + break; + } - if (i == null) + if (i == null) + { + if (dependecyValue == null) { - if(dependecyValue == null) + switch (parameterBag.PID) { - switch (parameterBag.PID) - { - case ERDM_Parameter.STATUS_ID_DESCRIPTION: - break; - default: - Logger?.LogDebug($"No {nameof(dependecyValue)} found for {parameterBag.PID}"); - dependecyValue = (IComparable)intType.GetMaximum(); - break; - } + case ERDM_Parameter.STATUS_ID_DESCRIPTION: + case ERDM_Parameter.STATUS_MESSAGES: + break; + default: + Logger?.LogDebug($"No {nameof(dependecyValue)} found for {parameterBag.PID}"); + dependecyValue = (IComparable)intType.GetMaximum(); + break; } - if (dependecyValue != null) + } + if (dependecyValue != null) + { + if (!dependecyValue.GetType().IsArray) { - if (!dependecyValue.GetType().IsArray) + i = intType.GetMinimum(); + object max = intType.GetMaximum(); + object count = Convert.ChangeType(0, i.GetType()); + object dataOutOfRangeMin = Convert.ChangeType(2, i.GetType()); + while (dependecyValue.CompareTo(count) > 0) { - 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 (!intType.IsInRange(i)) + continue; - if (((IComparable)max).CompareTo(i) == -1) - return new RequestResult(0); + if (((IComparable)max).CompareTo(i) == -1) + return new RequestResult(0); - 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.State == EPeerToPeerProcessState.Failed && ptpProcess.NackReason.Contains(ERDM_NackReason.DATA_OUT_OF_RANGE)) + 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.State == EPeerToPeerProcessState.Failed && ptpProcess.NackReason == ERDM_NackReason.DATA_OUT_OF_RANGE) + { + if (((IComparable)dataOutOfRangeMin).CompareTo(i) < 0) return new RequestResult(ptpProcess); - if (!ptpProcess.ResponsePayloadObject.IsUnset) - updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ptpProcess.ParameterBag.PID, i), ptpProcess.ResponsePayloadObject); - - i = intType.IncrementJumpRange(i); - count = intType.Increment(count); } + if (!ptpProcess.ResponsePayloadObject.IsUnset) + updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ptpProcess.ParameterBag.PID, i), ptpProcess.ResponsePayloadObject); + + i = intType.IncrementJumpRange(i); + count = intType.Increment(count); } - else + } + else + { + foreach (var item in (Array)dependecyValue) { - foreach (var item in (Array)dependecyValue) - { - var type = item.GetType(); - i = type.GetProperty(depBag.Key.Property); - 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(ptpProcess.ParameterBag.PID, i), ptpProcess.ResponsePayloadObject); - } + var type = item.GetType(); + i = type.GetProperty(depBag.Key.Property); + 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(ptpProcess.ParameterBag.PID, i), ptpProcess.ResponsePayloadObject); } - return new RequestResult(0); } - } - else - { - 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(ptpProcess.ParameterBag.PID, parameterBag.PID == ERDM_Parameter.QUEUED_MESSAGE || parameterBag.PID == ERDM_Parameter.STATUS_MESSAGES ? null : i), ptpProcess.ResponsePayloadObject); - return new RequestResult(ptpProcess); + return new RequestResult(0); } } - catch (Exception e) + else { - Logger?.LogError(e, $"Failed to get parameter {parameterBag.PID} with Bag: {parameterBag}"); + 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(ptpProcess.ParameterBag.PID, parameterBag.PID == ERDM_Parameter.QUEUED_MESSAGE || parameterBag.PID == ERDM_Parameter.STATUS_MESSAGES ? null : i), ptpProcess.ResponsePayloadObject); + return new RequestResult(ptpProcess); } } - return new RequestResult(0); + catch (Exception e) + { + Logger?.LogError(e, $"Failed to get parameter {parameterBag.PID} with Bag: {parameterBag}"); + } } + return new RequestResult(0); + } - public void Dispose() - { - if (this.IsDisposed || this.IsDisposing) - return; + public void Dispose() + { + if (this.IsDisposed || this.IsDisposing) + return; - this.IsDisposing = true; + this.IsDisposing = true; - this.parameterValues.Clear(); - this.parameterValues = null; - this.parameterValuesDataTreeBranch.Clear(); - this.parameterValuesDataTreeBranch = null; - this.parameterValuesDependeciePropertyBag.Clear(); - this.parameterValuesDependeciePropertyBag = null; - this.IsDisposed = true; - this.IsDisposing = false; - } + this.parameterValues.Clear(); + this.parameterValues = null; + this.parameterValuesDataTreeBranch.Clear(); + this.parameterValuesDataTreeBranch = null; + this.parameterValuesDependeciePropertyBag.Clear(); + this.parameterValuesDependeciePropertyBag = null; + this.IsDisposed = true; + this.IsDisposing = false; + } - public class RequestResult - { - public readonly byte MessageCounter; - public readonly EPeerToPeerProcessState State; - public readonly Exception Exception; + public class RequestResult + { + public readonly byte MessageCounter; + public readonly EPeerToPeerProcessState State; + public readonly Exception Exception; - public RequestResult(PeerToPeerProcess peerToPeerProcess) : this(peerToPeerProcess.MessageCounter, peerToPeerProcess.State) - { - Exception = peerToPeerProcess.Exception; - } - public RequestResult(byte messageCounter, EPeerToPeerProcessState state) - { - MessageCounter = messageCounter; - State = state; - } - public RequestResult(byte messageCounter) - { - MessageCounter = messageCounter; - } + public RequestResult(PeerToPeerProcess peerToPeerProcess) : this(peerToPeerProcess.MessageCounter, peerToPeerProcess.State) + { + Exception = peerToPeerProcess.Exception; + } + public RequestResult(byte messageCounter, EPeerToPeerProcessState state) + { + MessageCounter = messageCounter; + State = state; + } + public RequestResult(byte messageCounter) + { + MessageCounter = messageCounter; } } } \ No newline at end of file diff --git a/RDMSharp/RDM/Device/AbstractRemoteRDMDevice.cs b/RDMSharp/RDM/Device/AbstractRemoteRDMDevice.cs index 22569f4..04e8b73 100644 --- a/RDMSharp/RDM/Device/AbstractRemoteRDMDevice.cs +++ b/RDMSharp/RDM/Device/AbstractRemoteRDMDevice.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using RDMSharp.Metadata; +using RDMSharp.RDM.Device; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -8,573 +9,599 @@ using System.Threading; using System.Threading.Tasks; -namespace RDMSharp +namespace RDMSharp; + +public interface IRDMRemoteDevice : IRDMDevice { - public interface IRDMRemoteDevice: IRDMDevice - { - bool AllDataPulled { get; } - bool Present { get; } - DateTime LastSeen { get; } - Task SetParameter(ERDM_Parameter parameter, object value = null); - } - public interface IRDMRemoteSubDevice : IRDMRemoteDevice - { - } - public abstract class AbstractRemoteRDMDevice : AbstractRDMDevice , IRDMRemoteDevice - { - public sealed override bool IsGenerated => false; + bool AllDataPulled { get; } + bool Present { get; } + DateTime LastSeen { get; } + Task SetParameter(ERDM_Parameter parameter, object value = null); +} +public interface IRDMRemoteSubDevice : IRDMRemoteDevice +{ +} +public abstract class AbstractRemoteRDMDevice : AbstractRDMDevice, IRDMRemoteDevice +{ + public sealed override bool IsGenerated => false; - private readonly ConcurrentDictionary sensors = new ConcurrentDictionary(); - public sealed override IReadOnlyDictionary Sensors { get { return sensors.AsReadOnly(); } } - public sealed override IReadOnlyDictionary Slots { get { return PersonalityModel?.Slots; } } + private readonly ConcurrentDictionary sensors = new ConcurrentDictionary(); + public sealed override IReadOnlyDictionary Sensors { get { return sensors.AsReadOnly(); } } + public sealed override IReadOnlyDictionary Slots { get { return PersonalityModel?.Slots; } } - private readonly ConcurrentDictionary statusMessages = new ConcurrentDictionary(); - public sealed override IReadOnlyDictionary StatusMessages { get { return statusMessages.AsReadOnly(); } } + private readonly ConcurrentDictionary statusMessages = new ConcurrentDictionary(); + public sealed override IReadOnlyDictionary StatusMessages { get { return statusMessages.AsReadOnly(); } } - protected ConcurrentQueue ParameterUpdatedBag = new ConcurrentQueue(); + protected ConcurrentQueue ParameterUpdatedBag = new ConcurrentQueue(); - private RDMDeviceInfo deviceInfo; - public override RDMDeviceInfo DeviceInfo { get { return deviceInfo; } } + private RDMDeviceInfo deviceInfo; + public override RDMDeviceInfo DeviceInfo { get { return deviceInfo; } } - private RDMDeviceModel deviceModel; - public RDMDeviceModel DeviceModel + private RDMDeviceModel deviceModel; + public RDMDeviceModel DeviceModel + { + get { return deviceModel; } + private set { - get { return deviceModel; } - private set - { - if (deviceModel == value) - return; - deviceModel = value; - OnPropertyChanged(nameof(DeviceModel)); - } + if (deviceModel == value) + return; + deviceModel = value; + OnPropertyChanged(nameof(DeviceModel)); } - private RDMPersonalityModel personalityModel; - public RDMPersonalityModel PersonalityModel + } + private RDMPersonalityModel personalityModel; + public RDMPersonalityModel PersonalityModel + { + get { return personalityModel; } + private set { - get { return personalityModel; } - private set - { - if (personalityModel == value) - return; - personalityModel = value; - OnPropertyChanged(nameof(PersonalityModel)); - } + if (personalityModel == value) + return; + personalityModel = value; + OnPropertyChanged(nameof(PersonalityModel)); } - public sealed override IReadOnlyDictionary ParameterValues + } + public sealed override IReadOnlyDictionary ParameterValues + { + get { - get - { - if (DeviceModel == null) - return parameterValues.AsReadOnly(); + 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(); - } + return DeviceModel.ParameterValues.Where(x => !parameterValues.ContainsKey(x.Key)).Concat(parameterValues).ToDictionary(k => k.Key, v => v.Value).AsReadOnly(); } - - private bool allDataPulled; - public bool AllDataPulled + } + public sealed override IReadOnlyDictionary ParameterMetadataBag + { + get { - get - { - return allDataPulled; - } - private set - { - if (allDataPulled == value) - return; - allDataPulled = value; - OnPropertyChanged(nameof(AllDataPulled)); - } - } + IReadOnlyDictionary deviceModelParameterMetadataBag = null; + IReadOnlyDictionary personalityModelParameterMetadataBag = null; + if (PersonalityModel is not null) + personalityModelParameterMetadataBag = PersonalityModel.ParameterMetadataBag.Where(x => !parameterMetadataBag.ContainsKey(x.Key)).ToDictionary(k => k.Key, v => v.Value).AsReadOnly(); + if (DeviceModel is not null) + deviceModelParameterMetadataBag = DeviceModel.ParameterMetadataBag.Where(x => !parameterMetadataBag.ContainsKey(x.Key) && !(personalityModelParameterMetadataBag?.ContainsKey(x.Key) ?? false)).ToDictionary(k => k.Key, v => v.Value).AsReadOnly(); - private DateTime lastSeen; - public DateTime LastSeen - { - get - { - return lastSeen; - } - private set - { - if (lastSeen == value) - return; - lastSeen = value; - OnPropertyChanged(nameof(LastSeen)); - } - } + if (deviceModelParameterMetadataBag is not null || personalityModelParameterMetadataBag is not null) + return parameterMetadataBag.Concat(deviceModelParameterMetadataBag ?? Enumerable.Empty>()) + .Concat(personalityModelParameterMetadataBag ?? Enumerable.Empty>()) + .ToDictionary(k => k.Key, v => v.Value) + .AsReadOnly(); - private DateTime lastSendQueuedMessage; + return parameterMetadataBag.AsReadOnly(); + } + } - private bool present; - public bool Present + private bool allDataPulled; + public bool AllDataPulled + { + get { - get - { - return present; - } - internal set - { - if (present == value) - return; - present = value; - OnPropertyChanged(nameof(Present)); - } + return allDataPulled; } - - private bool queuedSupported = true; - public bool QueuedSupported + private set { - get - { - return queuedSupported; - } - private set - { - if (queuedSupported == value) - return; - queuedSupported = value; - OnPropertyChanged(nameof(QueuedSupported)); - } + if (allDataPulled == value) + return; + allDataPulled = value; + OnPropertyChanged(nameof(AllDataPulled)); } + } - - public AbstractRemoteRDMDevice(UID uid) : base(uid) + private DateTime lastSeen; + public DateTime LastSeen + { + get { + return lastSeen; } - public AbstractRemoteRDMDevice(UID uid, SubDevice? subDevice = null) : base(uid, subDevice) + private set { - if (subDevice.HasValue && subDevice.Value.IsBroadcast) - throw new NotSupportedException("A SubDevice can't be Broadcast."); + if (lastSeen == value) + return; + lastSeen = value; + OnPropertyChanged(nameof(LastSeen)); } - protected override async Task initialize(RDMDeviceInfo deviceInfo = null) + } + + private DateTime lastSendQueuedMessage; + + private bool present; + public bool Present + { + get { - Logger?.LogDebug($"Remote RDM Device {UID} SubDevice: {Subdevice} initializing."); - await base.initialize(deviceInfo); - GlobalTimers.Instance.PresentUpdateTimerElapsed += Instance_PresentUpdateTimerElapsed; - ParameterValueAdded += AbstractRDMDevice_ParameterValueAdded; - ParameterValueChanged += AbstractRDMDevice_ParameterValueChanged; - ParameterRequested += AbstractRDMDevice_ParameterRequested; - await requestDeviceInfo(deviceInfo); - Logger ?.LogDebug($"Remote RDM Device {UID} SubDevice: {Subdevice} initialized."); + return present; } - - private void Instance_PresentUpdateTimerElapsed(object sender, EventArgs e) + internal set { - Present = DateTime.UtcNow - lastSeen < TimeSpan.FromMilliseconds(GlobalTimers.Instance.PresentLostTime); + if (present == value) + return; + present = value; + OnPropertyChanged(nameof(Present)); } + } - private async void DeviceModel_Initialized(object sender, EventArgs e) + private bool queuedSupported = true; + public bool QueuedSupported + { + get { - deviceModel.Initialized -= DeviceModel_Initialized; - deviceModel.ParameterValueAdded -= DeviceModel_ParameterValueAdded; - await getPersonalityModelAndCollectAllParameters(); - await collectParameters(); + return queuedSupported; } - private async Task collectParameters() + private set { - await collectAllParametersOnRoot(); - await scanSubDevices(); - AllDataPulled = true; - GlobalTimers.Instance.ParameterUpdateTimerElapsed += Instance_ParameterUpdateTimerElapsed; + if (queuedSupported == value) + return; + queuedSupported = value; + OnPropertyChanged(nameof(QueuedSupported)); } + } - private async Task scanSubDevices() - { - if (DeviceInfo.SubDeviceCount == 0) - return; - if (!this.Subdevice.IsRoot) - return; - ushort foundSubDevices = 0; - ushort currentID = 0; - var dict = new Dictionary(); - while (foundSubDevices < DeviceInfo.SubDeviceCount) - { - currentID++; - if (currentID > 512) - break; + public AbstractRemoteRDMDevice(UID uid) : base(uid) + { + } + public AbstractRemoteRDMDevice(UID uid, SubDevice? subDevice = null) : base(uid, subDevice) + { + if (subDevice.HasValue && subDevice.Value.IsBroadcast) + throw new NotSupportedException("A SubDevice can't be Broadcast."); + } + protected override async Task initialize(RDMDeviceInfo deviceInfo = null) + { + Logger?.LogDebug($"Remote RDM Device {UID} SubDevice: {Subdevice} initializing."); + await base.initialize(deviceInfo); + GlobalTimers.Instance.PresentUpdateTimerElapsed += Instance_PresentUpdateTimerElapsed; + ParameterValueAdded += AbstractRDMDevice_ParameterValueAdded; + ParameterValueChanged += AbstractRDMDevice_ParameterValueChanged; + ParameterRequested += AbstractRDMDevice_ParameterRequested; + await requestDeviceInfo(deviceInfo); + Logger?.LogDebug($"Remote RDM Device {UID} SubDevice: {Subdevice} initialized."); + } - PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.GET_COMMAND, UID, new SubDevice(currentID), new ParameterBag(ERDM_Parameter.DEVICE_INFO)); - await runPeerToPeerProcess(ptpProcess); - if (ptpProcess.ResponsePayloadObject.ParsedObject is RDMDeviceInfo _deviceInfo) - { - foundSubDevices++; - var subDevice = createSubDevice(UID, ptpProcess.SubDevice); - this.SubDevices_Internal.Add(subDevice); - dict.Add(ptpProcess.SubDevice, _deviceInfo); - } - await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenRequests); - } - foreach (AbstractRemoteRDMDevice sd in this.SubDevices_Internal) + private void Instance_PresentUpdateTimerElapsed(object sender, EventArgs e) + { + Present = DateTime.UtcNow - lastSeen < TimeSpan.FromMilliseconds(GlobalTimers.Instance.PresentLostTime); + } + + private async void DeviceModel_Initialized(object sender, EventArgs e) + { + deviceModel.Initialized -= DeviceModel_Initialized; + deviceModel.ParameterValueAdded -= DeviceModel_ParameterValueAdded; + await getPersonalityModelAndCollectAllParameters(); + await collectParameters(); + } + private async Task collectParameters() + { + await collectAllParametersOnRoot(); + await scanSubDevices(); + AllDataPulled = true; + GlobalTimers.Instance.ParameterUpdateTimerElapsed += Instance_ParameterUpdateTimerElapsed; + } + + private async Task scanSubDevices() + { + if (DeviceInfo.SubDeviceCount == 0) + return; + if (!this.Subdevice.IsRoot) + return; + + ushort foundSubDevices = 0; + ushort currentID = 0; + var dict = new Dictionary(); + while (foundSubDevices < DeviceInfo.SubDeviceCount) + { + currentID++; + if (currentID > 512) + break; + + PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.GET_COMMAND, UID, new SubDevice(currentID), new ParameterBag(ERDM_Parameter.DEVICE_INFO)); + await runPeerToPeerProcess(ptpProcess); + if (ptpProcess.ResponsePayloadObject.ParsedObject is RDMDeviceInfo _deviceInfo) { - if (sd.Subdevice.IsRoot) - continue; - sd.performInitialize(dict[sd.Subdevice]); + foundSubDevices++; + var subDevice = createSubDevice(UID, ptpProcess.SubDevice); + this.SubDevices_Internal.Add(subDevice); + dict.Add(ptpProcess.SubDevice, _deviceInfo); } + await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenRequests); } + foreach (AbstractRemoteRDMDevice sd in this.SubDevices_Internal) + { + if (sd.Subdevice.IsRoot) + continue; + sd.performInitialize(dict[sd.Subdevice]); + } + } - protected abstract IRDMRemoteSubDevice createSubDevice(UID uid, SubDevice subDevice); + protected abstract IRDMRemoteSubDevice createSubDevice(UID uid, SubDevice subDevice); - #region Requests + #region Requests - private async Task requestDeviceInfo(RDMDeviceInfo deviceInfo = null) + private async Task requestDeviceInfo(RDMDeviceInfo deviceInfo = null) + { + DataTreeBranch? rpl = null; + if (deviceInfo == null) { - DataTreeBranch? rpl = null; - if (deviceInfo == null) + PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.GET_COMMAND, UID, Subdevice, new ParameterBag(ERDM_Parameter.DEVICE_INFO)); + await runPeerToPeerProcess(ptpProcess); + rpl = ptpProcess.ResponsePayloadObject; + if (rpl.Value.ParsedObject is RDMDeviceInfo _deviceInfo) { - PeerToPeerProcess ptpProcess = new PeerToPeerProcess(ERDM_Command.GET_COMMAND, UID, Subdevice, new ParameterBag(ERDM_Parameter.DEVICE_INFO)); - await runPeerToPeerProcess(ptpProcess); - rpl= ptpProcess.ResponsePayloadObject; - if (rpl.Value.ParsedObject is RDMDeviceInfo _deviceInfo) - { - this.deviceInfo = _deviceInfo; - updateParameterValuesDependeciePropertyBag(ERDM_Parameter.DEVICE_INFO, ptpProcess.ResponsePayloadObject); - updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ERDM_Parameter.DEVICE_INFO), ptpProcess.ResponsePayloadObject); - await getDeviceModelAndCollectAllParameters(); - } - } - else - { - rpl = DataTreeBranch.FromObject(deviceInfo, null, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.DEVICE_INFO); - this.deviceInfo = deviceInfo; - updateParameterValuesDependeciePropertyBag(ERDM_Parameter.DEVICE_INFO, rpl.Value); - updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ERDM_Parameter.DEVICE_INFO), rpl.Value); + this.deviceInfo = _deviceInfo; + updateParameterValuesDependeciePropertyBag(ERDM_Parameter.DEVICE_INFO, ptpProcess.ResponsePayloadObject); + updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ERDM_Parameter.DEVICE_INFO), ptpProcess.ResponsePayloadObject); await getDeviceModelAndCollectAllParameters(); } } - private async Task requestParameters() + else { - var parameters = this.DeviceModel?.SupportedNonBlueprintParameters.OrderBy(p=>(ushort)p).ToList(); - if (parameters == null) - return; + rpl = DataTreeBranch.FromObject(deviceInfo, null, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.DEVICE_INFO); + this.deviceInfo = deviceInfo; + updateParameterValuesDependeciePropertyBag(ERDM_Parameter.DEVICE_INFO, rpl.Value); + updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(ERDM_Parameter.DEVICE_INFO), rpl.Value); + await getDeviceModelAndCollectAllParameters(); + } + } + private async Task requestParameters() + { + var parameters = this.DeviceModel?.SupportedNonBlueprintParameters.OrderBy(p => (ushort)p).ToList(); + if (parameters == null) + return; - foreach (ERDM_Parameter parameter in parameters) + foreach (ERDM_Parameter parameter in parameters) + { + switch (parameter) { - switch (parameter) - { - case ERDM_Parameter.DEVICE_INFO: - continue; - case ERDM_Parameter.QUEUED_MESSAGE: - continue; - case ERDM_Parameter.STATUS_MESSAGES: - await requestParameter(parameter, ERDM_Status.NONE); - continue; - } - await requestParameter(parameter); - await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenRequests); + case ERDM_Parameter.DEVICE_INFO: + continue; + case ERDM_Parameter.QUEUED_MESSAGE: + tryAddParameterMetadata(parameter); + continue; + case ERDM_Parameter.STATUS_MESSAGES: + await requestParameter(parameter, ERDM_Status.NONE); + continue; } + tryAddParameterMetadata(parameter); + await requestParameter(parameter); + await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenRequests); } - private async Task requestParameter(ERDM_Parameter parameter, object payload = null) + } + private async Task requestParameter(ERDM_Parameter parameter, object payload = null) + { + try { - try + ParameterBag parameterBag = new ParameterBag(parameter, this.DeviceModel.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); + var define = MetadataFactory.GetDefine(parameterBag); + if (define == null) { - ParameterBag parameterBag = new ParameterBag(parameter, this.DeviceModel.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); - var define = MetadataFactory.GetDefine(parameterBag); - if (define == null) - { - ConcurrentDictionary pd = null; - if (this.deviceModel.ParameterValues.TryGetValue(ERDM_Parameter.PARAMETER_DESCRIPTION, out var obj)) - pd = obj as ConcurrentDictionary; + ConcurrentDictionary pd = null; + if (this.deviceModel.ParameterValues.TryGetValue(ERDM_Parameter.PARAMETER_DESCRIPTION, out var obj)) + pd = obj as ConcurrentDictionary; - if ((pd?.TryGetValue((ushort)parameter, out var desc) ?? false) && desc is RDMParameterDescription pDesc) - { - if (pDesc.CommandClass.HasFlag(ERDM_CommandClass.GET)) - await requestGetParameterWithEmptyPayload(parameterBag, define, UID, Subdevice); - } - } - if (define?.GetRequest.HasValue ?? false) + if ((pd?.TryGetValue((ushort)parameter, out var desc) ?? false) && desc is RDMParameterDescription pDesc) { - if (define.GetRequest.Value.GetIsEmpty()) + if (pDesc.CommandClass.HasFlag(ERDM_CommandClass.GET)) await requestGetParameterWithEmptyPayload(parameterBag, define, UID, Subdevice); - else - await requestGetParameterWithPayload(parameterBag, define, UID, Subdevice, payload); } } - catch (Exception ex) + if (define?.GetRequest.HasValue ?? false) { - Logger?.LogError(ex); + if (define.GetRequest.Value.GetIsEmpty()) + await requestGetParameterWithEmptyPayload(parameterBag, define, UID, Subdevice); + else + await requestGetParameterWithPayload(parameterBag, define, UID, Subdevice, payload); } } - - private SemaphoreSlim updateSenaphoreSlim = new SemaphoreSlim(1); - private async Task updateParameters() + catch (Exception ex) { - if (QueuedSupported && deviceModel.KnownNotSupportedParameters.Contains(ERDM_Parameter.QUEUED_MESSAGE)) - QueuedSupported = false; + Logger?.LogError(ex); + } + } - if (updateSenaphoreSlim.CurrentCount == 0) - return; + private SemaphoreSlim updateSenaphoreSlim = new SemaphoreSlim(1); + private async Task updateParameters() + { + if (QueuedSupported && deviceModel.KnownNotSupportedParameters.Contains(ERDM_Parameter.QUEUED_MESSAGE)) + QueuedSupported = false; + + if (updateSenaphoreSlim.CurrentCount == 0) + return; - await updateSenaphoreSlim.WaitAsync(); - try + await updateSenaphoreSlim.WaitAsync(); + try + { + await requestQueuedMessages(); + while (ParameterUpdatedBag.TryPeek(out ParameterUpdatedBag bag)) { - if (QueuedSupported && !deviceModel.KnownNotSupportedParameters.Contains(ERDM_Parameter.QUEUED_MESSAGE)) - { - if (DateTime.UtcNow - lastSendQueuedMessage < TimeSpan.FromMilliseconds(GlobalTimers.Instance.QueuedUpdateTime)) - return; - ParameterBag parameterBag = new ParameterBag(ERDM_Parameter.QUEUED_MESSAGE, this.DeviceModel.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); - var define = MetadataFactory.GetDefine(parameterBag); - if (define.GetRequest.HasValue) - { - byte mc = 0; - do - { - var cts = new CancellationTokenSource(); - cts.CancelAfter(TimeSpan.FromMilliseconds(GlobalTimers.Instance.ParameterUpdateTimerInterval)); - var task = Task.Run(async () => - { - lastSendQueuedMessage = DateTime.UtcNow; - - Stopwatch sw = new Stopwatch(); - sw?.Restart(); - var result = await requestGetParameterWithPayload(parameterBag, define, UID, Subdevice, ERDM_Status.ADVISORY); - mc = result.MessageCounter; - sw?.Stop(); - if (result.State == PeerToPeerProcess.EPeerToPeerProcessState.Failed) - { - if (sw.Elapsed.TotalSeconds > 3) - QueuedSupported = false; - Logger?.LogWarning($"Queued Parameter failed after {sw.ElapsedMilliseconds}ms, Queued seems not supported, and wil be disabled"); - return; - } - Logger?.LogTrace($"Queued Parameter update took {sw.ElapsedMilliseconds}ms for {mc} messages."); - }, cts.Token); - await task; - - if (task.IsCompletedSuccessfully) - await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenQueuedUpdateRequests); - else - { - Logger?.LogTrace(task.Exception, $"Queue Parameter update failed: {task.Exception?.Message}"); - return; - } + if (DateTime.UtcNow - bag.Timestamp < TimeSpan.FromMilliseconds(GlobalTimers.Instance.NonQueuedUpdateTime)) + return; - } - while (mc != 0); - return; - } - } - while (ParameterUpdatedBag.TryPeek(out ParameterUpdatedBag bag)) + var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromMilliseconds(GlobalTimers.Instance.ParameterUpdateTimerInterval)); + var task = Task.Run(async () => { - if (DateTime.UtcNow - bag.Timestamp < TimeSpan.FromMilliseconds(GlobalTimers.Instance.NonQueuedUpdateTime)) - return; + Stopwatch sw = new Stopwatch(); + sw?.Restart(); + await requestParameter(bag.Parameter, bag.Index); + sw?.Stop(); + Logger?.LogTrace($"Parameter update for {bag.Parameter} with index {bag.Index} took {sw.ElapsedMilliseconds}ms"); + + UpdateParameterUpdatedBag(bag.Parameter, bag.Index); + }, cts.Token); + await task; + + if (task.IsCompletedSuccessfully) + await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenNonQueuedUpdateRequests); + else + Logger?.LogTrace(task.Exception, $"Parameter update for {bag.Parameter} with index {bag.Index} failed: {task.Exception?.Message}"); + } + } + catch (Exception ex) + { + Logger?.LogError(ex); + } + finally + { + updateSenaphoreSlim.Release(); + } + } + private async Task requestQueuedMessages() + { + if (QueuedSupported && !deviceModel.KnownNotSupportedParameters.Contains(ERDM_Parameter.QUEUED_MESSAGE)) + { + if (DateTime.UtcNow - lastSendQueuedMessage < TimeSpan.FromMilliseconds(GlobalTimers.Instance.QueuedUpdateTime)) + return; + ParameterBag parameterBag = new ParameterBag(ERDM_Parameter.QUEUED_MESSAGE, this.DeviceModel.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); + var define = MetadataFactory.GetDefine(parameterBag); + if (define.GetRequest.HasValue) + { + byte mc = 0; + do + { var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromMilliseconds(GlobalTimers.Instance.ParameterUpdateTimerInterval)); var task = Task.Run(async () => { + lastSendQueuedMessage = DateTime.UtcNow; + Stopwatch sw = new Stopwatch(); sw?.Restart(); - await requestParameter(bag.Parameter, bag.Index); + var result = await requestGetParameterWithPayload(parameterBag, define, UID, Subdevice, ERDM_Status.ADVISORY); + mc = result.MessageCounter; sw?.Stop(); - Logger?.LogTrace($"Parameter update for {bag.Parameter} with index {bag.Index} took {sw.ElapsedMilliseconds}ms"); - - UpdateParameterUpdatedBag(bag.Parameter, bag.Index); + if (result.State == PeerToPeerProcess.EPeerToPeerProcessState.Failed) + { + if (sw.Elapsed.TotalSeconds > 3) + QueuedSupported = false; + Logger?.LogWarning($"Queued Parameter failed after {sw.ElapsedMilliseconds}ms, Queued seems not supported, and wil be disabled"); + return; + } + Logger?.LogTrace($"Queued Parameter update took {sw.ElapsedMilliseconds}ms for {mc} messages."); }, cts.Token); await task; if (task.IsCompletedSuccessfully) - await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenNonQueuedUpdateRequests); + await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenQueuedUpdateRequests); else - Logger?.LogTrace(task.Exception, $"Parameter update for {bag.Parameter} with index {bag.Index} failed: {task.Exception?.Message}"); + { + Logger?.LogTrace(task.Exception, $"Queue Parameter update failed: {task.Exception?.Message}"); + return; + } + } - } - catch (Exception ex) - { - Logger?.LogError(ex); - } - finally - { - updateSenaphoreSlim.Release(); + while (mc != 0); + return; } } + } - #endregion - private async Task getDeviceModelAndCollectAllParameters() - { - if (deviceModel != null) - return; - deviceModel = RDMDeviceModel.getDeviceModel(UID, Subdevice, DeviceInfo, new Func(RDMSharp.Instance.SendMessage)); - if (!deviceModel.IsInitialized) - { - deviceModel.Initialized += DeviceModel_Initialized; - deviceModel.ParameterValueAdded += DeviceModel_ParameterValueAdded; - if (!deviceModel.IsInitializing) - await deviceModel.Initialize(); - else - InvkoeDeviceModelParameterValueAdded(); - } + #endregion + private async Task getDeviceModelAndCollectAllParameters() + { + if (deviceModel != null) + return; + deviceModel = RDMDeviceModel.getDeviceModel(UID, Subdevice, DeviceInfo, new Func(RDMSharp.Instance.SendMessage)); + if (!deviceModel.IsInitialized) + { + deviceModel.Initialized += DeviceModel_Initialized; + deviceModel.ParameterValueAdded += DeviceModel_ParameterValueAdded; + if (!deviceModel.IsInitializing) + await deviceModel.Initialize(); else - { InvkoeDeviceModelParameterValueAdded(); - await collectParameters(); - } - void InvkoeDeviceModelParameterValueAdded() - { - foreach (var item in this.deviceModel.ParameterValues) - base.InvokeParameterValueAdded(new ParameterValueAddedEventArgs(item.Key, item.Value)); - } } - - private void DeviceModel_ParameterValueAdded(object sender, ParameterValueAddedEventArgs e) + else { - base.InvokeParameterValueAdded(e); + InvkoeDeviceModelParameterValueAdded(); + await collectParameters(); } - - private async Task collectAllParametersOnRoot() + void InvkoeDeviceModelParameterValueAdded() { - await requestParameters(); + foreach (var item in this.deviceModel.ParameterValues) + base.InvokeParameterValueAdded(new ParameterValueAddedEventArgs(item.Key, item.Value)); } + } - private async Task getPersonalityModelAndCollectAllParameters() - { - byte? personalityId = DeviceInfo.Dmx512CurrentPersonality.Value; - if (parameterValues.TryGetValue(ERDM_Parameter.DMX_PERSONALITY, out object value) && value is RDMDMXPersonality personality) - personalityId = personality.CurrentPersonality; + private void DeviceModel_ParameterValueAdded(object sender, ParameterValueAddedEventArgs e) + { + base.InvokeParameterValueAdded(e); + } - PersonalityModel = DeviceModel.getPersonalityModel(this, personalityId ?? 0); - if (!PersonalityModel.IsInitialized) - await PersonalityModel.Initialize(); - } + private async Task collectAllParametersOnRoot() + { + await requestParameters(); + } - private async void AbstractRDMDevice_ParameterValueAdded(object sender, ParameterValueAddedEventArgs e) - { - switch (e.Parameter) - { - case ERDM_Parameter.DMX_PERSONALITY: - if (DeviceModel.IsInitialized) - await getPersonalityModelAndCollectAllParameters(); - break; - case ERDM_Parameter.SENSOR_VALUE when e.Value is RDMSensorValue sensorValue: - var sensor = sensors.GetOrAdd(sensorValue.SensorId, (a) => new Sensor(a)); - if (deviceModel.GetSensorDefinitions()?.FirstOrDefault(a => a.SensorId == sensorValue.SensorId) is RDMSensorDefinition sd) - sensor.UpdateDescription(sd); - sensor.UpdateValue(sensorValue); - break; - } + private async Task getPersonalityModelAndCollectAllParameters() + { + byte? personalityId = DeviceInfo.Dmx512CurrentPersonality.Value; + if (parameterValues.TryGetValue(ERDM_Parameter.DMX_PERSONALITY, out object value) && value is RDMDMXPersonality personality) + personalityId = personality.CurrentPersonality; + + PersonalityModel = DeviceModel.getPersonalityModel(this, personalityId ?? 0); + if (!PersonalityModel.IsInitialized) + await PersonalityModel.Initialize(); + } + + private async void AbstractRDMDevice_ParameterValueAdded(object sender, ParameterValueAddedEventArgs e) + { + switch (e.Parameter) + { + case ERDM_Parameter.DMX_PERSONALITY: + if (DeviceModel.IsInitialized) + await getPersonalityModelAndCollectAllParameters(); + break; + case ERDM_Parameter.SENSOR_VALUE when e.Value is RDMSensorValue sensorValue: + var sensor = sensors.GetOrAdd(sensorValue.SensorId, (a) => new Sensor(a)); + if (deviceModel.GetSensorDefinitions()?.FirstOrDefault(a => a.SensorId == sensorValue.SensorId) is RDMSensorDefinition sd) + sensor.UpdateDescription(sd); + sensor.UpdateValue(sensorValue); + break; } - private async void AbstractRDMDevice_ParameterValueChanged(object sender, ParameterValueChangedEventArgs e) - { - switch (e.Parameter) - { - case ERDM_Parameter.DEVICE_INFO: - if (this.PersonalityModel.PersonalityID != this.DeviceInfo.Dmx512CurrentPersonality) - goto case ERDM_Parameter.DMX_PERSONALITY; - break; - case ERDM_Parameter.DMX_PERSONALITY: - if (DeviceModel.IsInitialized) - await getPersonalityModelAndCollectAllParameters(); - break; - case ERDM_Parameter.SENSOR_VALUE when e.NewValue is RDMSensorValue sensorValue: - if (sensorValue.SensorId == byte.MaxValue) //Ignore Broadcast as in Spec. - break; - var sensor = sensors.GetOrAdd(sensorValue.SensorId, (a) => new Sensor(a)); - sensor.UpdateValue(sensorValue); + } + private async void AbstractRDMDevice_ParameterValueChanged(object sender, ParameterValueChangedEventArgs e) + { + switch (e.Parameter) + { + case ERDM_Parameter.DEVICE_INFO: + if (this.PersonalityModel.PersonalityID != this.DeviceInfo.Dmx512CurrentPersonality) + goto case ERDM_Parameter.DMX_PERSONALITY; + break; + case ERDM_Parameter.DMX_PERSONALITY: + if (DeviceModel.IsInitialized) + await getPersonalityModelAndCollectAllParameters(); + break; + case ERDM_Parameter.SENSOR_VALUE when e.NewValue is RDMSensorValue sensorValue: + if (sensorValue.SensorId == byte.MaxValue) //Ignore Broadcast as in Spec. break; - } - } - private void AbstractRDMDevice_ParameterRequested(object sender, ParameterRequestedEventArgs e) - { - LastSeen = DateTime.UtcNow; - UpdateParameterUpdatedBag(e.Parameter, e.Index); + var sensor = sensors.GetOrAdd(sensorValue.SensorId, (a) => new Sensor(a)); + sensor.UpdateValue(sensorValue); + break; } - private void UpdateParameterUpdatedBag(ERDM_Parameter parameter, object index) + } + private void AbstractRDMDevice_ParameterRequested(object sender, ParameterRequestedEventArgs e) + { + LastSeen = DateTime.UtcNow; + UpdateParameterUpdatedBag(e.Parameter, e.Index); + } + private void UpdateParameterUpdatedBag(ERDM_Parameter parameter, object index) + { + if (!Constants.BLUEPRINT_MODEL_PARAMETERS.Contains(parameter) && !Constants.BLUEPRINT_MODEL_PERSONALITY_PARAMETERS.Contains(parameter)) { - if (!Constants.BLUEPRINT_MODEL_PARAMETERS.Contains(parameter) && !Constants.BLUEPRINT_MODEL_PERSONALITY_PARAMETERS.Contains(parameter)) + if (ParameterUpdatedBag.Any(p => p.Parameter == parameter && p.Index == index)) { - if (ParameterUpdatedBag.Any(p => p.Parameter == parameter && p.Index == index)) - { - var tempQueue = new ConcurrentQueue(); - while (ParameterUpdatedBag.TryDequeue(out var item)) - if (!(item.Parameter.Equals(parameter) && Equals(item.Index, index))) - tempQueue.Enqueue(item); + var tempQueue = new ConcurrentQueue(); + while (ParameterUpdatedBag.TryDequeue(out var item)) + if (!(item.Parameter.Equals(parameter) && Equals(item.Index, index))) + tempQueue.Enqueue(item); - while (tempQueue.TryDequeue(out var item)) - ParameterUpdatedBag.Enqueue(item); - } - ParameterUpdatedBag.Enqueue(new ParameterUpdatedBag(parameter, index)); + while (tempQueue.TryDequeue(out var item)) + ParameterUpdatedBag.Enqueue(item); } + ParameterUpdatedBag.Enqueue(new ParameterUpdatedBag(parameter, index)); } + } - public async Task SetParameter(ERDM_Parameter parameter, object value = null) + public async Task SetParameter(ERDM_Parameter parameter, object value = null) + { + try { - try + ParameterBag parameterBag = new ParameterBag(parameter, this.DeviceModel.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); + var define = MetadataFactory.GetDefine(parameterBag); + if (define.SetRequest.HasValue) { - ParameterBag parameterBag = new ParameterBag(parameter, this.DeviceModel.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); - var define = MetadataFactory.GetDefine(parameterBag); - if (define.SetRequest.HasValue) - { - if (define.SetRequest.Value.GetIsEmpty()) - return await requestSetParameterWithEmptyPayload(parameterBag, define, UID, Subdevice); - else - return await requestSetParameterWithPayload(parameterBag, define, UID, Subdevice, value); - } - } - catch (Exception e) - { - Logger?.LogError(string.Empty, e); + if (define.SetRequest.Value.GetIsEmpty()) + return await requestSetParameterWithEmptyPayload(parameterBag, define, UID, Subdevice); + else + return await requestSetParameterWithPayload(parameterBag, define, UID, Subdevice, value); } - return false; } - - protected sealed override async Task OnResponseMessage(RDMMessage rdmMessage) + catch (Exception e) { - LastSeen = DateTime.UtcNow; + Logger?.LogError(string.Empty, e); + } + return false; + } - if (rdmMessage?.ResponseType == ERDM_ResponseType.NACK_REASON) - this.deviceModel?.handleNACKReason(rdmMessage); + protected sealed override async Task OnResponseMessage(RDMMessage rdmMessage) + { + LastSeen = DateTime.UtcNow; - await base.OnResponseMessage(rdmMessage); - } + if (rdmMessage?.ResponseType == ERDM_ResponseType.NACK_REASON) + this.deviceModel?.handleNACKReason(rdmMessage); - public sealed override IReadOnlyDictionary GetAllParameterValues() - { + await base.OnResponseMessage(rdmMessage); + } - IReadOnlyDictionary res = null; - if (this.DeviceModel is not null) - res = this.DeviceModel.ParameterValues; - if(this.PersonalityModel is not null) - res=res.Concat(this.PersonalityModel.ParameterValues) - .ToLookup(x => x.Key, x => x.Value) - .ToDictionary(x => x.Key, g => g.First()); ; - if (res is not null) - return res.Concat(this.ParameterValues) - .ToLookup(x => x.Key, x => x.Value) - .ToDictionary(x => x.Key, g => g.First()); - else - return base.GetAllParameterValues(); - } + public sealed override IReadOnlyDictionary GetAllParameterValues() + { + + IReadOnlyDictionary res = null; + if (this.DeviceModel is not null) + res = this.DeviceModel.ParameterValues; + if (this.PersonalityModel is not null) + res = res.Concat(this.PersonalityModel.ParameterValues) + .ToLookup(x => x.Key, x => x.Value) + .ToDictionary(x => x.Key, g => g.First()); ; + if (res is not null) + return res.Concat(this.ParameterValues) + .ToLookup(x => x.Key, x => x.Value) + .ToDictionary(x => x.Key, g => g.First()); + else + return base.GetAllParameterValues(); + } - private async void Instance_ParameterUpdateTimerElapsed(object sender, EventArgs e) - { - await updateParameters(); - } + private async void Instance_ParameterUpdateTimerElapsed(object sender, EventArgs e) + { + await updateParameters(); + } - public override string ToString() + public override string ToString() + { + return $"{base.ToString()} {this.DeviceModel}"; + } + protected sealed override void OnDispose() + { + GlobalTimers.Instance.PresentUpdateTimerElapsed -= Instance_PresentUpdateTimerElapsed; + GlobalTimers.Instance.ParameterUpdateTimerElapsed -= Instance_ParameterUpdateTimerElapsed; + try { - return $"{base.ToString()} {this.DeviceModel}"; + onDispose(); } - protected sealed override void OnDispose() + catch (Exception e) { - GlobalTimers.Instance.PresentUpdateTimerElapsed -= Instance_PresentUpdateTimerElapsed; - GlobalTimers.Instance.ParameterUpdateTimerElapsed -= Instance_ParameterUpdateTimerElapsed; - try - { - onDispose(); - } - catch (Exception e) - { - Logger?.LogError(e); - } - ParameterValueAdded -= AbstractRDMDevice_ParameterValueAdded; - ParameterValueChanged -= AbstractRDMDevice_ParameterValueChanged; - ParameterRequested -= AbstractRDMDevice_ParameterRequested; + Logger?.LogError(e); } - protected abstract void onDispose(); - - + ParameterValueAdded -= AbstractRDMDevice_ParameterValueAdded; + ParameterValueChanged -= AbstractRDMDevice_ParameterValueChanged; + ParameterRequested -= AbstractRDMDevice_ParameterRequested; } + protected abstract void onDispose(); + + } \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/AbstractModule.cs b/RDMSharp/RDM/Device/Module/AbstractModule.cs new file mode 100644 index 0000000..0190c8c --- /dev/null +++ b/RDMSharp/RDM/Device/Module/AbstractModule.cs @@ -0,0 +1,87 @@ +using Microsoft.Extensions.Logging; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace RDMSharp.RDM.Device.Module +{ + public abstract class AbstractModule : IModule + { + protected static ILogger Logger = Logging.CreateLogger(); + + public event PropertyChangedEventHandler PropertyChanged; + + private readonly string _name; + public string Name { get => _name; } + + private readonly IReadOnlyCollection _supportedParameters; + + public IReadOnlyCollection SupportedParameters { get => _supportedParameters; } + + protected AbstractGeneratedRDMDevice ParentDevice { get; private set; } + + public AbstractModule(string name, params ERDM_Parameter[] supportedParameters) + { + this._name = name; + this._supportedParameters = supportedParameters; + } + public RDMMessage? HandleRequest(RDMMessage message) + { + if (!this.IsHandlingParameter(message.Parameter, message.Command)) + return null; + + ERDM_NackReason? nackReason = null; + try + { + return handleRequest(message); + } + catch (System.Exception ex) + { + nackReason = ERDM_NackReason.HARDWARE_FAULT; + } + return new RDMMessage(nackReason ?? ERDM_NackReason.UNKNOWN_PID) + { + DestUID = message.SourceUID, + SourceUID = message.SourceUID, + Command = ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE, + Parameter = message.Parameter + }; + } + protected virtual RDMMessage? handleRequest(RDMMessage message) + { + throw new System.NotImplementedException("This method should be overridden in derived classes to handle specific requests."); + } + + public virtual bool IsHandlingParameter(ERDM_Parameter parameter, ERDM_Command command) + { + return false; + } + + internal void SetParentDevice(AbstractGeneratedRDMDevice device) + { + if (ParentDevice is not null) + return; + ParentDevice = device; + device.ParameterValueAdded += Device_ParameterValueAdded; + device.ParameterValueChanged += Device_ParameterValueChanged; + OnParentDeviceChanged(ParentDevice); + } + + private void Device_ParameterValueAdded(object sender, AbstractRDMCache.ParameterValueAddedEventArgs e) + { + ParameterChanged(e.Parameter, e.Value, e.Index); + } + private void Device_ParameterValueChanged(object sender, AbstractRDMCache.ParameterValueChangedEventArgs e) + { + ParameterChanged(e.Parameter, e.NewValue, e.Index); + } + protected abstract void ParameterChanged(ERDM_Parameter parameter, object? newValue, object? index); + + protected abstract void OnParentDeviceChanged(AbstractGeneratedRDMDevice device); + + protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/BootSoftwareVersionModule.cs b/RDMSharp/RDM/Device/Module/BootSoftwareVersionModule.cs new file mode 100644 index 0000000..7b92a74 --- /dev/null +++ b/RDMSharp/RDM/Device/Module/BootSoftwareVersionModule.cs @@ -0,0 +1,70 @@ +namespace RDMSharp.RDM.Device.Module +{ + public sealed class BootSoftwareVersionModule : AbstractModule + { + private uint _bootSoftwareVersionId; + private string _bootSoftwareVersionLabel; + public uint BootSoftwareVersionId + { + get + { + if (ParentDevice is null) + return _bootSoftwareVersionId; + object res; + if (ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID, out res)) + return (uint)res; + return _bootSoftwareVersionId; + } + internal set { + _bootSoftwareVersionId = value; + if (ParentDevice is not null) + ParentDevice.setParameterValue(ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID, value); + } + } + public string BootSoftwareVersionLabel + { + get + { + if (ParentDevice is null) + return _bootSoftwareVersionLabel; + object res; + if (ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL, out res)) + return (string)res; + return _bootSoftwareVersionLabel; + } + internal set + { + _bootSoftwareVersionLabel = value; + if (ParentDevice is not null) + ParentDevice.setParameterValue(ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL, value); + } + } + public BootSoftwareVersionModule(uint bootSoftwareVersionId, string bootSoftwareVersionLabel) : base( + "BootSoftwareVersion", + ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID, + ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL) + { + _bootSoftwareVersionId = bootSoftwareVersionId; + _bootSoftwareVersionLabel = bootSoftwareVersionLabel; + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + this.BootSoftwareVersionId = _bootSoftwareVersionId; + this.BootSoftwareVersionLabel = _bootSoftwareVersionLabel; + } + + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + switch (parameter) + { + case ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID: + OnPropertyChanged(nameof(BootSoftwareVersionId)); + break; + case ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL: + OnPropertyChanged(nameof(BootSoftwareVersionLabel)); + break; + } + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/DMX_PersonalityModule.cs b/RDMSharp/RDM/Device/Module/DMX_PersonalityModule.cs new file mode 100644 index 0000000..99157d0 --- /dev/null +++ b/RDMSharp/RDM/Device/Module/DMX_PersonalityModule.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace RDMSharp.RDM.Device.Module +{ + public sealed class DMX_PersonalityModule : AbstractModule + { + private byte _currentPersonality; + public byte? CurrentPersonality + { + get + { + if (ParentDevice is null) + return _currentPersonality; + object res; + if (ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.DMX_PERSONALITY, out res)) + if (res is RDMDMXPersonality personality) + return personality.CurrentPersonality; + return _currentPersonality; + } + set + { + if (!value.HasValue) + throw new NullReferenceException($"{CurrentPersonality} can't be null if {ERDM_Parameter.DMX_PERSONALITY} is Supported"); + if (value.Value == 0) + throw new ArgumentOutOfRangeException($"{CurrentPersonality} can't 0 if {ERDM_Parameter.DMX_PERSONALITY} is Supported"); + + if (!this.Personalities.Any(p => p.ID == value.Value)) + throw new ArgumentOutOfRangeException($"No Personality found with ID: {value.Value}"); + + _currentPersonality = value.Value; + if (ParentDevice is not null) + ParentDevice.setParameterValue(ERDM_Parameter.DMX_PERSONALITY, new RDMDMXPersonality(value.Value, PersonalitiesCount)); + } + } + public IReadOnlyCollection PersonalityDesriptions + { + get + { + if (ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION, out object res)) + if (res is ConcurrentDictionary dict) + return dict.Select(d => d.Value).OfType().ToList().AsReadOnly(); + return Array.Empty(); + } + } + public readonly IReadOnlyCollection Personalities; + public readonly byte PersonalitiesCount; + private ushort currentPersonalityFootprint; + public ushort CurrentPersonalityFootprint + { + get + { + return currentPersonalityFootprint; + } + private set + { + if (currentPersonalityFootprint == value) + return; + currentPersonalityFootprint = value; + OnPropertyChanged(); + } + } + + public DMX_PersonalityModule(byte currentPersonality, params GeneratedPersonality[] personalities) : base( + "DMX_Personality", + ERDM_Parameter.DMX_PERSONALITY, + ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION) + { + if (!personalities.Any(p => p.ID == currentPersonality)) + throw new ArgumentOutOfRangeException($"No Personality found with ID: {currentPersonality}"); + + _currentPersonality = currentPersonality; + Personalities = (personalities ?? Array.Empty()).ToList().AsReadOnly(); + PersonalitiesCount = (byte)Personalities.Count; + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + if (Personalities is not null) + { + if (Personalities.Count >= byte.MaxValue) + throw new ArgumentOutOfRangeException($"There to many {Personalities}! Maximum is {byte.MaxValue - 1}"); + + if (Personalities.Count != 0) + { + var persDesc = new ConcurrentDictionary(); + foreach (var gPers in Personalities) + if (!persDesc.TryAdd(gPers.ID, (RDMDMXPersonalityDescription)gPers)) + throw new Exception($"{gPers.ID} already used as {nameof(gPers.ID)}"); + + device.setParameterValue(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION, persDesc); + } + } + this.CurrentPersonality = _currentPersonality; + } + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + switch (parameter) + { + case ERDM_Parameter.DMX_PERSONALITY: + OnPropertyChanged(nameof(CurrentPersonality)); + byte? val = null; + if (newValue is RDMDMXPersonality personality) + val = personality.OfPersonalities; + else if (newValue is byte b) + val = b; + if (val.HasValue) + { + CurrentPersonalityFootprint = Personalities.FirstOrDefault(p => p.ID == val.Value)?.SlotCount ?? 0; + return; + } + CurrentPersonalityFootprint = 0; + break; + case ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION: + OnPropertyChanged(nameof(Personalities)); + break; + } + } + public override bool IsHandlingParameter(ERDM_Parameter parameter, ERDM_Command command) + { + if (parameter == ERDM_Parameter.DMX_PERSONALITY) + return command == ERDM_Command.SET_COMMAND; + return base.IsHandlingParameter(parameter, command); + } + protected override RDMMessage handleRequest(RDMMessage message) + { + if (message.Parameter == ERDM_Parameter.DMX_PERSONALITY) + if (message.Command == ERDM_Command.SET_COMMAND) + { + if (message.Value is byte b) + { + try + { + if (this.Personalities.Any(p => p.ID == b)) + CurrentPersonality = b; + else + { + return new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) + { + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + Command = ERDM_Command.SET_COMMAND_RESPONSE + }; + } + } + catch (Exception ex) + { + Logger?.LogError(ex); + return new RDMMessage(ERDM_NackReason.HARDWARE_FAULT) + { + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + Command = ERDM_Command.SET_COMMAND_RESPONSE + }; + } + return new RDMMessage() + { + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + }; + } + return new RDMMessage(ERDM_NackReason.FORMAT_ERROR) + { + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + Command = ERDM_Command.SET_COMMAND_RESPONSE + }; + } + return base.handleRequest(message); + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/DMX_StartAddressModule.cs b/RDMSharp/RDM/Device/Module/DMX_StartAddressModule.cs new file mode 100644 index 0000000..81da741 --- /dev/null +++ b/RDMSharp/RDM/Device/Module/DMX_StartAddressModule.cs @@ -0,0 +1,54 @@ +using System; + +namespace RDMSharp.RDM.Device.Module +{ + public sealed class DMX_StartAddressModule : AbstractModule + { + private ushort _dmxAddress; + public ushort? DMXAddress + { + get + { + if (ParentDevice is null) + return _dmxAddress; + object res; + if (ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.DMX_START_ADDRESS, out res)) + return (ushort?)res; + return _dmxAddress; + } + set + { + if (!value.HasValue) + throw new NullReferenceException($"{DMXAddress} can't be null if {ERDM_Parameter.DMX_START_ADDRESS} is Supported"); + if (value.Value == 0) + throw new ArgumentOutOfRangeException($"{DMXAddress} can't 0 if {ERDM_Parameter.DMX_START_ADDRESS} is Supported"); + if (value.Value > 512) + throw new ArgumentOutOfRangeException($"{DMXAddress} can't be greater then 512"); + + _dmxAddress = value.Value; + if (ParentDevice is not null) + ParentDevice.setParameterValue(ERDM_Parameter.DMX_START_ADDRESS, value); + } + } + public DMX_StartAddressModule(ushort dmxAddress) : base( + "DMX_StartAddress", + ERDM_Parameter.DMX_START_ADDRESS) + { + _dmxAddress = dmxAddress; + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + this.DMXAddress = _dmxAddress; + } + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + switch (parameter) + { + case ERDM_Parameter.DMX_START_ADDRESS: + OnPropertyChanged(nameof(DMXAddress)); + break; + } + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/DeviceInfoModule.cs b/RDMSharp/RDM/Device/Module/DeviceInfoModule.cs new file mode 100644 index 0000000..9cc677e --- /dev/null +++ b/RDMSharp/RDM/Device/Module/DeviceInfoModule.cs @@ -0,0 +1,75 @@ +using System; +using System.Linq; + +namespace RDMSharp.RDM.Device.Module +{ + public sealed class DeviceInfoModule : AbstractModule + { + public RDMDeviceInfo DeviceInfo + { + get + { + object res; + if (ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.DEVICE_INFO, out res)) + return (RDMDeviceInfo)res; + return null; + } + internal set + { + if (ParentDevice is not null) + ParentDevice.setParameterValue(ERDM_Parameter.DEVICE_INFO, value); + } + } + private SoftwareVersionModule softwareVersionModule; + private DMX_StartAddressModule dmxStartAddressModule; + private DMX_PersonalityModule dmxPersonalityModule; + private SensorsModule sensorsModule; + + public DeviceInfoModule() : base( + "DeviceInfo", + ERDM_Parameter.DEVICE_INFO) + { + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + softwareVersionModule = device.Modules.OfType().FirstOrDefault(); + dmxStartAddressModule = device.Modules.OfType().FirstOrDefault(); + dmxPersonalityModule = device.Modules.OfType().FirstOrDefault(); + sensorsModule = device.Modules.OfType().FirstOrDefault(); + updateParameterValues(); + } + private void updateParameterValues() + { + if (ParentDevice is null) + return; + this.DeviceInfo = new RDMDeviceInfo(1, + 0, + ParentDevice.DeviceModelID, + ParentDevice.ProductCategoryCoarse, + ParentDevice.ProductCategoryFine, + softwareVersionModule?.SoftwareVersionId ?? 0, + dmx512Footprint: dmxPersonalityModule?.CurrentPersonalityFootprint ?? 0, + dmx512CurrentPersonality: dmxPersonalityModule?.CurrentPersonality ?? 0, + dmx512NumberOfPersonalities: dmxPersonalityModule?.PersonalitiesCount ?? 0, + dmx512StartAddress: (dmxStartAddressModule?.DMXAddress ?? ushort.MaxValue), + subDeviceCount: (ushort)(ParentDevice.SubDevices?.Where(sd => !sd.Subdevice.IsRoot).Count() ?? 0), + sensorCount: (byte)(sensorsModule?.Sensors?.Count ?? 0)); + + OnPropertyChanged(nameof(DeviceInfo)); + } + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + switch (parameter) + { + case ERDM_Parameter.DEVICE_INFO: + OnPropertyChanged(nameof(DeviceInfo)); + break; + case ERDM_Parameter.DMX_PERSONALITY: + case ERDM_Parameter.DMX_START_ADDRESS: + updateParameterValues(); + break; + } + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/DeviceLabelModule.cs b/RDMSharp/RDM/Device/Module/DeviceLabelModule.cs new file mode 100644 index 0000000..4884288 --- /dev/null +++ b/RDMSharp/RDM/Device/Module/DeviceLabelModule.cs @@ -0,0 +1,45 @@ +namespace RDMSharp.RDM.Device.Module +{ + public sealed class DeviceLabelModule : AbstractModule + { + private string _deviceLabel; + public string DeviceLabel + { + get + { + if (ParentDevice is null) + return _deviceLabel; + object res; + if (ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.DEVICE_LABEL, out res)) + return (string)res; + return _deviceLabel; + } + internal set + { + _deviceLabel = value; + if (ParentDevice is not null) + ParentDevice.setParameterValue(ERDM_Parameter.DEVICE_LABEL, value); + } + } + public DeviceLabelModule(string deviceLabel) : base( + "DeviceLabel", + ERDM_Parameter.DEVICE_LABEL) + { + _deviceLabel = deviceLabel; + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + this.DeviceLabel = _deviceLabel; + } + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + switch (parameter) + { + case ERDM_Parameter.DEVICE_LABEL: + OnPropertyChanged(nameof(DeviceLabel)); + break; + } + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/DeviceModelDescriptionModule.cs b/RDMSharp/RDM/Device/Module/DeviceModelDescriptionModule.cs new file mode 100644 index 0000000..e1adf8a --- /dev/null +++ b/RDMSharp/RDM/Device/Module/DeviceModelDescriptionModule.cs @@ -0,0 +1,45 @@ +namespace RDMSharp.RDM.Device.Module +{ + public sealed class DeviceModelDescriptionModule : AbstractModule + { + private string _deviceModelDescriptionLabel; + public string DeviceModelDescription + { + get + { + if (ParentDevice is null) + return _deviceModelDescriptionLabel; + object res; + if (ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.DEVICE_MODEL_DESCRIPTION, out res)) + return (string)res; + return _deviceModelDescriptionLabel; + } + internal set + { + _deviceModelDescriptionLabel = value; + if (ParentDevice is not null) + ParentDevice.setParameterValue(ERDM_Parameter.DEVICE_MODEL_DESCRIPTION, value); + } + } + public DeviceModelDescriptionModule(string manufacturerLabel) : base( + "DeviceModelDescription", + ERDM_Parameter.DEVICE_MODEL_DESCRIPTION) + { + _deviceModelDescriptionLabel = manufacturerLabel; + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + this.DeviceModelDescription = _deviceModelDescriptionLabel; + } + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + switch (parameter) + { + case ERDM_Parameter.DEVICE_MODEL_DESCRIPTION: + OnPropertyChanged(nameof(DeviceModelDescription)); + break; + } + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/IModule.cs b/RDMSharp/RDM/Device/Module/IModule.cs new file mode 100644 index 0000000..2330008 --- /dev/null +++ b/RDMSharp/RDM/Device/Module/IModule.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.ComponentModel; + +namespace RDMSharp.RDM.Device.Module +{ + public interface IModule: INotifyPropertyChanged + { + string Name { get; } + IReadOnlyCollection SupportedParameters { get; } + + RDMMessage? HandleRequest(RDMMessage message); + bool IsHandlingParameter(ERDM_Parameter parameter, ERDM_Command command); + } +} diff --git a/RDMSharp/RDM/Device/Module/IdentifyDeviceModule.cs b/RDMSharp/RDM/Device/Module/IdentifyDeviceModule.cs new file mode 100644 index 0000000..e8d382a --- /dev/null +++ b/RDMSharp/RDM/Device/Module/IdentifyDeviceModule.cs @@ -0,0 +1,47 @@ +using System; + +namespace RDMSharp.RDM.Device.Module +{ + public sealed class IdentifyDeviceModule : AbstractModule + { + private bool _identify; + public bool Identify + { + get + { + if (ParentDevice is null) + return _identify; + object res; + if (ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.IDENTIFY_DEVICE, out res)) + return (bool)res; + return _identify; + } + internal set + { + _identify = value; + if (ParentDevice is not null) + ParentDevice.setParameterValue(ERDM_Parameter.IDENTIFY_DEVICE, value); + } + } + + public IdentifyDeviceModule() : base( + "IdentifyDevice", + ERDM_Parameter.IDENTIFY_DEVICE) + { + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + this.Identify = _identify; + } + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + switch (parameter) + { + case ERDM_Parameter.IDENTIFY_DEVICE: + OnPropertyChanged(nameof(Identify)); + break; + } + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/InterfaceModule.cs b/RDMSharp/RDM/Device/Module/InterfaceModule.cs new file mode 100644 index 0000000..37c0353 --- /dev/null +++ b/RDMSharp/RDM/Device/Module/InterfaceModule.cs @@ -0,0 +1,277 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace RDMSharp.RDM.Device.Module +{ + public sealed class InterfaceModule : AbstractModule + { + private IReadOnlyCollection _interfaces; + public IReadOnlyCollection Interfaces + { + get + { + return _interfaces; + } + } + private ConcurrentDictionary lableDict = new ConcurrentDictionary(); + private ConcurrentDictionary hardwareAddressTypeDict = new ConcurrentDictionary(); + private ConcurrentDictionary currentAddressDict = new ConcurrentDictionary(); + private ConcurrentDictionary staticAddressDict = new ConcurrentDictionary(); + private ConcurrentDictionary dhcpModeDict = new ConcurrentDictionary(); + private ConcurrentDictionary zeroConfModeDict = new ConcurrentDictionary(); + + private ConcurrentDictionary> applyConfigQueueDict = new ConcurrentDictionary>(); + public InterfaceModule(IReadOnlyCollection interfaces) : base( + "Interface", + 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) + { + _interfaces = interfaces; + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + + foreach (var iface in _interfaces) + { + lableDict.TryAdd(iface.InterfaceId, new GetInterfaceNameResponse(iface.InterfaceId, iface.Lable)); + hardwareAddressTypeDict.TryAdd(iface.InterfaceId, new GetHardwareAddressResponse(iface.InterfaceId, iface.MACAddress)); + currentAddressDict.TryAdd(iface.InterfaceId, new GetIPv4CurrentAddressResponse(iface.InterfaceId, iface.CurrentIP, iface.CurrentSubnetMask, (byte)(iface.DHCP ? 1 : 0))); + staticAddressDict.TryAdd(iface.InterfaceId, new GetSetIPv4StaticAddress(iface.InterfaceId, iface.StaticIP, iface.StaticSubnetMask)); + dhcpModeDict.TryAdd(iface.InterfaceId, new GetSetIPV4_xxx_Mode(iface.InterfaceId, iface.DHCP)); + zeroConfModeDict.TryAdd(iface.InterfaceId, new GetSetIPV4_xxx_Mode(iface.InterfaceId, iface.ZeroConf)); + iface.PropertyChanged += Iface_PropertyChanged; + } + + ParentDevice.setParameterValue(ERDM_Parameter.INTERFACE_LABEL, lableDict); + ParentDevice.setParameterValue(ERDM_Parameter.INTERFACE_HARDWARE_ADDRESS_TYPE, hardwareAddressTypeDict); + ParentDevice.setParameterValue(ERDM_Parameter.IPV4_CURRENT_ADDRESS, currentAddressDict); + ParentDevice.setParameterValue(ERDM_Parameter.IPV4_STATIC_ADDRESS, staticAddressDict); + ParentDevice.setParameterValue(ERDM_Parameter.IPV4_DHCP_MODE, dhcpModeDict); + ParentDevice.setParameterValue(ERDM_Parameter.IPV4_ZEROCONF_MODE, zeroConfModeDict); + ParentDevice.setParameterValue(ERDM_Parameter.LIST_INTERFACES, _interfaces.Select(i => new InterfaceDescriptor(i.InterfaceId, i.HardwareType)).ToArray()); + } + + private void Iface_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (sender is not Interface iface) + return; + switch (e.PropertyName) + { + case (nameof(Interface.DHCP)): + var newDHCPValue = new GetSetIPV4_xxx_Mode(iface.InterfaceId, iface.DHCP); + this.dhcpModeDict.AddOrUpdate(iface.InterfaceId, (_) => newDHCPValue, (_, _) => newDHCPValue); + this.ParentDevice.setParameterValue(ERDM_Parameter.IPV4_DHCP_MODE, this.dhcpModeDict, iface.InterfaceId); + break; + case (nameof(Interface.ZeroConf)): + var newZeroConfValue = new GetSetIPV4_xxx_Mode(iface.InterfaceId, iface.ZeroConf); + this.zeroConfModeDict.AddOrUpdate(iface.InterfaceId, (_) => newZeroConfValue, (_, _) => newZeroConfValue); + this.ParentDevice.setParameterValue(ERDM_Parameter.IPV4_ZEROCONF_MODE, this.zeroConfModeDict, iface.InterfaceId); + break; + + case (nameof(Interface.StaticIP)): + case (nameof(Interface.StaticSubnetMask)): + var newIPv4StaticAddressValue = new GetSetIPv4StaticAddress(iface.InterfaceId, iface.StaticIP, iface.StaticSubnetMask); + this.staticAddressDict.AddOrUpdate(iface.InterfaceId, (_) => newIPv4StaticAddressValue, (_, _) => newIPv4StaticAddressValue); + this.ParentDevice.setParameterValue(ERDM_Parameter.IPV4_STATIC_ADDRESS, this.staticAddressDict, iface.InterfaceId); + break; + case (nameof(Interface.CurrentIP)): + case (nameof(Interface.CurrentSubnetMask)): + var newIPv4CurrentAddressValue = new GetIPv4CurrentAddressResponse(iface.InterfaceId, iface.StaticIP, iface.StaticSubnetMask); + this.currentAddressDict.AddOrUpdate(iface.InterfaceId, (_) => newIPv4CurrentAddressValue, (_, _) => newIPv4CurrentAddressValue); + this.ParentDevice.setParameterValue(ERDM_Parameter.IPV4_CURRENT_ADDRESS, this.currentAddressDict, iface.InterfaceId); + break; + } + } + + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + Interface? iface = null; + if (index is not null && index is uint ui) + iface = _interfaces.FirstOrDefault(iface => iface.InterfaceId == ui); + + if (newValue is ConcurrentDictionary dict && index is not null) + newValue = dict.GetValueOrDefault(index); + + switch (parameter) + { + case ERDM_Parameter.LIST_INTERFACES: + OnPropertyChanged(nameof(Interfaces)); + break; + case ERDM_Parameter.IPV4_DHCP_MODE: + if (iface is not null) + iface.DHCP = ((GetSetIPV4_xxx_Mode)newValue).Enabled; + break; + case ERDM_Parameter.IPV4_ZEROCONF_MODE: + if (iface is not null) + iface.ZeroConf = ((GetSetIPV4_xxx_Mode)newValue).Enabled; + break; + } + } + protected override RDMMessage handleRequest(RDMMessage message) + { + switch (message.Parameter) + { + case ERDM_Parameter.IPV4_ZEROCONF_MODE when message.Command is ERDM_Command.SET_COMMAND: + case ERDM_Parameter.IPV4_DHCP_MODE when message.Command is ERDM_Command.SET_COMMAND: + case ERDM_Parameter.IPV4_STATIC_ADDRESS when message.Command is ERDM_Command.SET_COMMAND: + case ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION when message.Command is ERDM_Command.SET_COMMAND: + if (message.Value is null) + return new RDMMessage(ERDM_NackReason.FORMAT_ERROR) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + + if (message.PDL >= 4) + { + byte[] parameterData = message.ParameterData.Take(4).ToArray(); + uint interfaceId = message.ParameterData.Length > 0 ? Tools.DataToUInt(ref parameterData) : 0; + + if (_interfaces.FirstOrDefault(iface => iface.InterfaceId == interfaceId) is not Interface iface) + return new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + try + { +#if DEBUG + if (message.SourceUID.Equals(new UID(0xeeee, 0xf0f0f0f0))) + throw new System.Exception("Simulated hardware fault for testing purposes."); +#endif + if (message.Parameter != ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION) + applyConfigQueueDict.GetOrAdd(interfaceId, (_) => { return new ConcurrentQueue(); }).Enqueue(new RDMMessage(message.BuildMessage())); + else + { + if (applyConfigQueueDict.TryGetValue(interfaceId, out ConcurrentQueue queue)) + while (queue.TryDequeue(out RDMMessage applyMessage)) + { + switch (applyMessage.Parameter) + { + case ERDM_Parameter.IPV4_DHCP_MODE when applyMessage.Value is GetSetIPV4_xxx_Mode dhcpMode: + iface.DHCP = dhcpMode.Enabled; + break; + case ERDM_Parameter.IPV4_ZEROCONF_MODE when applyMessage.Value is GetSetIPV4_xxx_Mode zeroConfMode: + iface.ZeroConf = zeroConfMode.Enabled; + break; + case ERDM_Parameter.IPV4_STATIC_ADDRESS when applyMessage.Value is GetSetIPv4StaticAddress staticAddress: + iface.SetStaticIP(staticAddress.IPAddress, staticAddress.Netmask); + break; + } + } + } + + return new RDMMessage() + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + } + catch (Exception ex) + { + Logger?.LogError(ex); + } + } + break; + case ERDM_Parameter.INTERFACE_RENEW_DHCP when message.Command is ERDM_Command.SET_COMMAND: + case ERDM_Parameter.INTERFACE_RELEASE_DHCP when message.Command is ERDM_Command.SET_COMMAND: + if (message.Value is not uint ifaceId) + return new RDMMessage(ERDM_NackReason.FORMAT_ERROR) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + if (_interfaces.FirstOrDefault(iface => iface.InterfaceId == ifaceId) is not Interface iface2) + return new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + try + { + switch (message.Parameter) + { + case ERDM_Parameter.INTERFACE_RENEW_DHCP: + if (iface2.StaticIP != IPv4Address.Empty || !iface2.DHCP) + return new RDMMessage(ERDM_NackReason.ACTION_NOT_SUPPORTED) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + iface2.RenewDHCP(); + break; + case ERDM_Parameter.INTERFACE_RELEASE_DHCP: + if (iface2.CurrentIP_DHCPStatus != ERDM_DHCPStatusMode.ACTIVE) + return new RDMMessage(ERDM_NackReason.ACTION_NOT_SUPPORTED) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + iface2.ReleaseDHCP(); + break; + } + } + catch(Exception ex) + { + Logger?.LogError(ex); + } + return new RDMMessage() + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + break; + default: + break; + } + return new RDMMessage(ERDM_NackReason.HARDWARE_FAULT) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = message.Command | ERDM_Command.RESPONSE, + Parameter = message.Parameter + }; + } + public override bool IsHandlingParameter(ERDM_Parameter parameter, ERDM_Command command) + { + switch (parameter) + { + case ERDM_Parameter.IPV4_DHCP_MODE when command is ERDM_Command.SET_COMMAND: + case ERDM_Parameter.IPV4_ZEROCONF_MODE when command is ERDM_Command.SET_COMMAND: + case ERDM_Parameter.IPV4_STATIC_ADDRESS when command is ERDM_Command.SET_COMMAND: + case ERDM_Parameter.INTERFACE_RENEW_DHCP when command is ERDM_Command.SET_COMMAND: + case ERDM_Parameter.INTERFACE_RELEASE_DHCP when command is ERDM_Command.SET_COMMAND: + case ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION when command is ERDM_Command.SET_COMMAND: + return true; + } + return base.IsHandlingParameter(parameter, command); + } + } +} diff --git a/RDMSharp/RDM/Device/Module/ManufacturerLabelModule.cs b/RDMSharp/RDM/Device/Module/ManufacturerLabelModule.cs new file mode 100644 index 0000000..a5df9ca --- /dev/null +++ b/RDMSharp/RDM/Device/Module/ManufacturerLabelModule.cs @@ -0,0 +1,49 @@ +using System; + +namespace RDMSharp.RDM.Device.Module +{ + public sealed class ManufacturerLabelModule : AbstractModule + { + private string _manufacturerLabel; + public string ManufacturerLabel + { + get + { + if (ParentDevice is null) + return _manufacturerLabel; + object res; + if (ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.MANUFACTURER_LABEL, out res)) + return (string)res; + return _manufacturerLabel; + } + internal set + { + _manufacturerLabel = value; + if (ParentDevice is not null) + ParentDevice.setParameterValue(ERDM_Parameter.MANUFACTURER_LABEL, value); + } + } + public ManufacturerLabelModule(string manufacturerLabel) : base( + "ManufacturerLabel", + ERDM_Parameter.MANUFACTURER_LABEL) + { + _manufacturerLabel = manufacturerLabel; + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + if (string.IsNullOrWhiteSpace(_manufacturerLabel)) + _manufacturerLabel = Enum.GetName(typeof(EManufacturer), (EManufacturer)device.UID.ManufacturerID); + this.ManufacturerLabel = _manufacturerLabel; + } + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + switch (parameter) + { + case ERDM_Parameter.MANUFACTURER_LABEL: + OnPropertyChanged(nameof(ManufacturerLabel)); + break; + } + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/PresetsModule.cs b/RDMSharp/RDM/Device/Module/PresetsModule.cs new file mode 100644 index 0000000..8606604 --- /dev/null +++ b/RDMSharp/RDM/Device/Module/PresetsModule.cs @@ -0,0 +1,27 @@ +namespace RDMSharp.RDM.Device.Module +{ + public sealed class PresetsModule : AbstractModule + { + public PresetsModule() : base( + "Presets", + ERDM_Parameter.PRESET_PLAYBACK, + ERDM_Parameter.CAPTURE_PRESET) + { + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + throw new System.NotImplementedException(); + } + + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + throw new System.NotImplementedException(); + } + + //protected override RDMMessage handleRequest(RDMMessage message) + //{ + // return null; + //} + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/ProxiedDevicesModule.cs b/RDMSharp/RDM/Device/Module/ProxiedDevicesModule.cs new file mode 100644 index 0000000..387384c --- /dev/null +++ b/RDMSharp/RDM/Device/Module/ProxiedDevicesModule.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace RDMSharp.RDM.Device.Module; + +public sealed class ProxiedDevicesModule : AbstractModule +{ + public IReadOnlyCollection DeviceUIDs + { + get + { + IReadOnlyCollection uidList = null; + if (this.ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.PROXIED_DEVICES, out object proxiedDevices)) + { + if (proxiedDevices is RDMProxiedDevices obj) + uidList = obj.Devices.ToList().AsReadOnly(); + } + return uidList; + } + } + private ConcurrentDictionary> proxiedDevicesOngoingTransaktions = new ConcurrentDictionary>(); + public ProxiedDevicesModule() : base( + "ProxiedDevices", + ERDM_Parameter.PROXIED_DEVICES, + ERDM_Parameter.PROXIED_DEVICES_COUNT) + { + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + this.ParentDevice.setParameterValue(ERDM_Parameter.PROXIED_DEVICES, new RDMProxiedDevices()); + this.ParentDevice.setParameterValue(ERDM_Parameter.PROXIED_DEVICES_COUNT, new RDMProxiedDeviceCount(0, false)); + } + + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + switch (parameter) + { + case ERDM_Parameter.PROXIED_DEVICES: + OnPropertyChanged(nameof(DeviceUIDs)); + break; + } + } + public override bool IsHandlingParameter(ERDM_Parameter parameter, ERDM_Command command) + { + switch (parameter) + { + case ERDM_Parameter.PROXIED_DEVICES: + case ERDM_Parameter.PROXIED_DEVICES_COUNT: + return true; // These parameters are handled by this module. + } + return false; // Default case, not handled by this module. + } + + protected override RDMMessage handleRequest(RDMMessage message) + { + switch (message.Parameter) + { + case ERDM_Parameter.PROXIED_DEVICES when message.Command is ERDM_Command.GET_COMMAND: + if (!proxiedDevicesOngoingTransaktions.ContainsKey(message.SourceUID)) + { + var devices = DeviceUIDs; + var chunks = devices.Chunk(38); + ConcurrentQueue queue = new ConcurrentQueue(); + byte messageCounter = (byte)chunks.Count(); + foreach (var chunk in chunks) + { + messageCounter--; + queue.Enqueue(new RDMMessage() + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.GET_COMMAND_RESPONSE, + Parameter = message.Parameter, + ControllerFlags_or_MessageCounter = messageCounter, + ParameterData = new RDMProxiedDevices(chunk).ToPayloadData() + }); + } + proxiedDevicesOngoingTransaktions.TryAdd(message.SourceUID, queue); + } + proxiedDevicesOngoingTransaktions.TryGetValue(message.SourceUID, out ConcurrentQueue msgQueue); + if (msgQueue != null && msgQueue.TryDequeue(out RDMMessage responseMessage)) + { + if (msgQueue.IsEmpty) + { + proxiedDevicesOngoingTransaktions.TryRemove(message.SourceUID, out _); + this.ParentDevice.setParameterValue(ERDM_Parameter.PROXIED_DEVICES_COUNT, new RDMProxiedDeviceCount((ushort)DeviceUIDs.Count, false)); + } + return responseMessage; + } + break; + + case ERDM_Parameter.PROXIED_DEVICES_COUNT when message.Command is ERDM_Command.GET_COMMAND: + return new RDMMessage() + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.GET_COMMAND_RESPONSE, + Parameter = message.Parameter, + ParameterData = (this.ParentDevice.GetAllParameterValues()[ERDM_Parameter.PROXIED_DEVICES_COUNT] as RDMProxiedDeviceCount).ToPayloadData() + }; + } + return new RDMMessage(ERDM_NackReason.HARDWARE_FAULT) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = message.Command | ERDM_Command.RESPONSE, + Parameter = message.Parameter + }; + } + + public void AddProxiedDevices(params UID[] deviceUIDs) + { + var currentDevices = this.ParentDevice.GetAllParameterValues()[ERDM_Parameter.PROXIED_DEVICES] as RDMProxiedDevices; + var devicesList = currentDevices.Devices.ToList(); + bool changed = false; + foreach (var deviceUID in deviceUIDs) + { + if (!devicesList.Contains(deviceUID)) + { + devicesList.Add(deviceUID); + changed = true; + } + } + if (changed) + { + this.ParentDevice.setParameterValue(ERDM_Parameter.PROXIED_DEVICES, new RDMProxiedDevices(devicesList.ToArray())); + this.ParentDevice.setParameterValue(ERDM_Parameter.PROXIED_DEVICES_COUNT, new RDMProxiedDeviceCount((ushort)devicesList.Count, true)); + OnPropertyChanged(nameof(DeviceUIDs)); + } + } + public void RemoveProxiedDevices(params UID[] deviceUIDs) + { + var currentDevices = this.ParentDevice.GetAllParameterValues()[ERDM_Parameter.PROXIED_DEVICES] as RDMProxiedDevices; + var devicesList = currentDevices.Devices.ToList(); + bool changed = false; + foreach (var deviceUID in deviceUIDs) + { + if (devicesList.Contains(deviceUID)) + { + devicesList.Remove(deviceUID); + changed = true; + } + } + if (changed) + { + this.ParentDevice.setParameterValue(ERDM_Parameter.PROXIED_DEVICES, new RDMProxiedDevices(devicesList.ToArray())); + this.ParentDevice.setParameterValue(ERDM_Parameter.PROXIED_DEVICES_COUNT, new RDMProxiedDeviceCount((ushort)devicesList.Count, true)); + OnPropertyChanged(nameof(DeviceUIDs)); + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/RealTimeClockModule.cs b/RDMSharp/RDM/Device/Module/RealTimeClockModule.cs new file mode 100644 index 0000000..5c5ab7b --- /dev/null +++ b/RDMSharp/RDM/Device/Module/RealTimeClockModule.cs @@ -0,0 +1,52 @@ +using System; + +namespace RDMSharp.RDM.Device.Module +{ + public sealed class RealTimeClockModule : AbstractModule + { + public DateTime? RealTimeClock + { + get + { + if (ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.REAL_TIME_CLOCK, out object res)) + { + if (res is DateTime dateTime) + return dateTime; + if (res is RDMRealTimeClock rdmRealTimeClock) + return rdmRealTimeClock.Date; + } + return null; + } + internal set + { + if (ParentDevice is not null) + ParentDevice.setParameterValue(ERDM_Parameter.REAL_TIME_CLOCK, new RDMRealTimeClock(value.Value)); + } + } + public RealTimeClockModule() : base( + "RealTimeClock", + ERDM_Parameter.REAL_TIME_CLOCK) + { + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + this.RealTimeClock = DateTime.Now; + GlobalTimers.Instance.PresentUpdateTimerElapsed += Instance_PresentUpdateTimerElapsed; + } + + private void Instance_PresentUpdateTimerElapsed(object sender, EventArgs e) + { + this.RealTimeClock= DateTime.Now; + } + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + switch (parameter) + { + case ERDM_Parameter.REAL_TIME_CLOCK: + OnPropertyChanged(nameof(RealTimeClock)); + break; + } + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/SelfTestsModule.cs b/RDMSharp/RDM/Device/Module/SelfTestsModule.cs new file mode 100644 index 0000000..8f890d2 --- /dev/null +++ b/RDMSharp/RDM/Device/Module/SelfTestsModule.cs @@ -0,0 +1,27 @@ +namespace RDMSharp.RDM.Device.Module +{ + public sealed class SelfTestsModule : AbstractModule + { + public SelfTestsModule() : base( + "SelfTests", + ERDM_Parameter.PERFORM_SELFTEST, + ERDM_Parameter.SELF_TEST_DESCRIPTION) + { + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + throw new System.NotImplementedException(); + } + + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + throw new System.NotImplementedException(); + } + + //protected override RDMMessage handleRequest(RDMMessage message) + //{ + // return null; + //} + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/SensorsModule.cs b/RDMSharp/RDM/Device/Module/SensorsModule.cs new file mode 100644 index 0000000..e3a9753 --- /dev/null +++ b/RDMSharp/RDM/Device/Module/SensorsModule.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace RDMSharp.RDM.Device.Module +{ + public sealed class SensorsModule : AbstractModule + { + private readonly ConcurrentDictionary sensors = new ConcurrentDictionary(); + public IReadOnlyDictionary Sensors + { + get + { + return sensors.AsReadOnly(); + } + } + + private ConcurrentDictionary sensorDef = new ConcurrentDictionary(); + private ConcurrentDictionary sensorValue = new ConcurrentDictionary(); + private ConcurrentDictionary sensorUnit; + private ConcurrentDictionary sensorType; + + public SensorsModule(params Sensor[] sensors) : base( + "Sensors", + getSupportedParameters(sensors)) + { + if (sensors is null) + throw new ArgumentNullException(nameof(sensors), "Sensors cannot be null."); + if (sensors.Length == 0) + throw new ArgumentException("Sensors cannot be empty.", nameof(sensors)); + + foreach (var sensor in sensors) + { + if (!this.sensors.TryAdd(sensor.SensorId, sensor)) + throw new ArgumentException($"Sensor with ID {sensor.SensorId} already exists in the SensorsModule."); + + if (!sensorDef.TryAdd(sensor.SensorId, (RDMSensorDefinition)sensor)) + 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)}"); + + if (sensor.CustomUnit is not null) + { + if(sensorUnit is null) + sensorUnit = new ConcurrentDictionary(); + sensorUnit.TryAdd(sensor.SensorId, sensor.CustomUnit); + } + if (sensor.CustomType is not null) + { + if (sensorType is null) + sensorType = new ConcurrentDictionary(); + sensorType.TryAdd(sensor.SensorId, sensor.CustomType); + } + + sensor.PropertyChanged += Sensor_PropertyChanged; + } + } + + private static ERDM_Parameter[] getSupportedParameters(Sensor[] sensors) + { + List supportedParameters = new List + { + ERDM_Parameter.SENSOR_DEFINITION, + ERDM_Parameter.SENSOR_VALUE + }; + if (sensors.Any(s => s.RecordedValueSupported)) + supportedParameters.Add(ERDM_Parameter.RECORD_SENSORS); + + if (sensors.Any(s => ((byte)s.Unit) >= 0x80)) + supportedParameters.Add(ERDM_Parameter.SENSOR_UNIT_CUSTOM); + + if (sensors.Any(s => ((byte)s.Type) >= 0x80)) + supportedParameters.Add(ERDM_Parameter.SENSOR_TYPE_CUSTOM); + + return supportedParameters.ToArray(); + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + this.ParentDevice.setParameterValue(ERDM_Parameter.SENSOR_DEFINITION, sensorDef); + this.ParentDevice.setParameterValue(ERDM_Parameter.SENSOR_VALUE, sensorValue); + if (sensorUnit is not null) + this.ParentDevice.setParameterValue(ERDM_Parameter.SENSOR_UNIT_CUSTOM, sensorUnit); + if (sensorType is not null) + this.ParentDevice.setParameterValue(ERDM_Parameter.SENSOR_TYPE_CUSTOM, sensorType); + } + + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + } + public override bool IsHandlingParameter(ERDM_Parameter parameter, ERDM_Command command) + { + if (parameter == ERDM_Parameter.RECORD_SENSORS) + return command == ERDM_Command.SET_COMMAND; + + return base.IsHandlingParameter(parameter, command); + } + protected override RDMMessage handleRequest(RDMMessage message) + { + if (message.Parameter == ERDM_Parameter.RECORD_SENSORS) + if (message.Command == ERDM_Command.SET_COMMAND) + { + if (message.Value is byte sensorID) + { + try + { + if (sensorID == 0xff)// Broadcast + foreach (var sensor in sensors.Values) + sensor.RecordValue(); + else if (sensors.ContainsKey(sensorID)) + sensors[sensorID].RecordValue(); + else + { + return new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) + { + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + Command = ERDM_Command.SET_COMMAND_RESPONSE + }; + } + } + catch (Exception ex) + { + Logger?.LogError(ex); + return new RDMMessage(ERDM_NackReason.HARDWARE_FAULT) + { + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + Command = ERDM_Command.SET_COMMAND_RESPONSE + }; + } + return new RDMMessage() + { + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + }; + } + return new RDMMessage(ERDM_NackReason.FORMAT_ERROR) + { + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + Command = ERDM_Command.SET_COMMAND_RESPONSE + }; + } + else + return new RDMMessage(ERDM_NackReason.UNSUPPORTED_COMMAND_CLASS) + { + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + Command = message.Command | ERDM_Command.RESPONSE + }; + return base.handleRequest(message); + } + private void Sensor_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (sender is not Sensor sensor) + return; + + switch (e.PropertyName) + { + case nameof(Sensor.Type): + case nameof(Sensor.Unit): + case nameof(Sensor.Prefix): + case nameof(Sensor.RangeMaximum): + case nameof(Sensor.RangeMinimum): + case nameof(Sensor.NormalMaximum): + case nameof(Sensor.NormalMinimum): + case nameof(Sensor.LowestHighestValueSupported): + case nameof(Sensor.RecordedValueSupported): + sensorDef.AddOrUpdate(sensor.SensorId, (RDMSensorDefinition)sensor, (o1, o2) => (RDMSensorDefinition)sensor); + this.ParentDevice.setParameterValue(ERDM_Parameter.SENSOR_DEFINITION, sensorDef, sensor.SensorId); + OnPropertyChanged(nameof(Sensors)); + break; + case nameof(Sensor.PresentValue): + case nameof(Sensor.LowestValue): + case nameof(Sensor.HighestValue): + case nameof(Sensor.RecordedValue): + sensorValue.AddOrUpdate(sensor.SensorId, (RDMSensorValue)sensor, (o1, o2) => (RDMSensorValue)sensor); + this.ParentDevice.setParameterValue(ERDM_Parameter.SENSOR_VALUE, sensorValue, sensor.SensorId); + OnPropertyChanged(nameof(Sensors)); + break; + } + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/SlotsModule.cs b/RDMSharp/RDM/Device/Module/SlotsModule.cs new file mode 100644 index 0000000..d7322b0 --- /dev/null +++ b/RDMSharp/RDM/Device/Module/SlotsModule.cs @@ -0,0 +1,72 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace RDMSharp.RDM.Device.Module +{ + public sealed class SlotsModule : AbstractModule + { + public IReadOnlyDictionary Slots + { + get + { + return dmxPersonalityModule?.Personalities?.FirstOrDefault(p=>p.ID == dmxPersonalityModule.CurrentPersonality)?.Slots; + } + } + + private DMX_PersonalityModule dmxPersonalityModule; + + public SlotsModule() : base( + "Slots", + ERDM_Parameter.SLOT_INFO, + ERDM_Parameter.SLOT_DESCRIPTION, + ERDM_Parameter.DEFAULT_SLOT_VALUE) + { + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + dmxPersonalityModule = device.Modules.OfType().FirstOrDefault(); + dmxPersonalityModule.PropertyChanged += DmxPersonalityModule_PropertyChanged; + updateParameterValues(); + } + + private void DmxPersonalityModule_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName != nameof(DMX_PersonalityModule.CurrentPersonality)) + return; + + updateParameterValues(); + } + + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + switch (parameter) + { + case ERDM_Parameter.DMX_PERSONALITY: + updateParameterValues(); + break; + } + } + private void updateParameterValues() + { + var slots = this.Slots; + var slotsCount = slots.Count; + var slotInfos = new RDMSlotInfo[slotsCount]; + var slotDesc = new ConcurrentDictionary(); + var slotDefault = new RDMDefaultSlotValue[slotsCount]; + foreach (var s in slots) + { + Slot slot = s.Value; + slotInfos[slot.SlotId] = new RDMSlotInfo(slot.SlotId, slot.Type, slot.Category); + slotDesc.TryAdd(slot.SlotId, new RDMSlotDescription(slot.SlotId, slot.Description)); + slotDefault[slot.SlotId] = new RDMDefaultSlotValue(slot.SlotId, slot.DefaultValue); + } + ParentDevice.setParameterValue(ERDM_Parameter.SLOT_INFO, slotInfos); + ParentDevice.setParameterValue(ERDM_Parameter.SLOT_DESCRIPTION, slotDesc); + ParentDevice.setParameterValue(ERDM_Parameter.DEFAULT_SLOT_VALUE, slotDefault); + OnPropertyChanged(nameof(Slots)); + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/SoftwareVersionModule.cs b/RDMSharp/RDM/Device/Module/SoftwareVersionModule.cs new file mode 100644 index 0000000..208e09e --- /dev/null +++ b/RDMSharp/RDM/Device/Module/SoftwareVersionModule.cs @@ -0,0 +1,59 @@ +namespace RDMSharp.RDM.Device.Module +{ + public sealed class SoftwareVersionModule : AbstractModule + { + private uint _softwareVersionId; + private string _softwareVersionLabel; + public uint SoftwareVersionId + { + get + { + return _softwareVersionId; + } + internal set + { + _softwareVersionId = value; + } + } + public string SoftwareVersionLabel + { + get + { + if (ParentDevice is null) + return _softwareVersionLabel; + object res; + if (ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.SOFTWARE_VERSION_LABEL, out res)) + return (string)res; + return _softwareVersionLabel; + } + internal set + { + _softwareVersionLabel = value; + if (ParentDevice is not null) + ParentDevice.setParameterValue(ERDM_Parameter.SOFTWARE_VERSION_LABEL, value); + } + } + public SoftwareVersionModule(uint softwareVersionId, string softwareVersionLabel) : base( + "SoftwareVersion", + ERDM_Parameter.SOFTWARE_VERSION_LABEL) + { + _softwareVersionId = softwareVersionId; + _softwareVersionLabel = softwareVersionLabel; + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + this.SoftwareVersionId = _softwareVersionId; + this.SoftwareVersionLabel = _softwareVersionLabel; + } + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + switch (parameter) + { + case ERDM_Parameter.SOFTWARE_VERSION_LABEL: + OnPropertyChanged(nameof(SoftwareVersionLabel)); + break; + } + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/StatusMessageModule.cs b/RDMSharp/RDM/Device/Module/StatusMessageModule.cs new file mode 100644 index 0000000..2cad253 --- /dev/null +++ b/RDMSharp/RDM/Device/Module/StatusMessageModule.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace RDMSharp.RDM.Device.Module +{ + public sealed class StatusMessageModule : AbstractModule + { + private ConcurrentDictionary statusMessages = new ConcurrentDictionary(); + public IReadOnlyDictionary StatusMessages { get { return statusMessages.AsReadOnly(); } } + public StatusMessageModule() : base( + "StatusMessage", + ERDM_Parameter.STATUS_MESSAGES, + ERDM_Parameter.CLEAR_STATUS_ID) + { + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + this.ParentDevice.setParameterValue(ERDM_Parameter.STATUS_MESSAGES, new RDMStatusMessage[0]); + } + + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + } + public override bool IsHandlingParameter(ERDM_Parameter parameter, ERDM_Command command) + { + if (parameter == ERDM_Parameter.CLEAR_STATUS_ID) + return true; + + return base.IsHandlingParameter(parameter, command); + } + protected override RDMMessage handleRequest(RDMMessage message) + { + if (message.Parameter == ERDM_Parameter.CLEAR_STATUS_ID) + if (message.Command == ERDM_Command.SET_COMMAND) + { + if (message.PDL == 0) + { + try + { + statusMessages?.Clear(); + OnPropertyChanged(nameof(StatusMessages)); + } + catch (Exception ex) + { + Logger?.LogError(ex); + return new RDMMessage(ERDM_NackReason.HARDWARE_FAULT) + { + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + Command = ERDM_Command.SET_COMMAND_RESPONSE + }; + } + return new RDMMessage() + { + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + }; + } + return new RDMMessage(ERDM_NackReason.FORMAT_ERROR) + { + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + Command = ERDM_Command.SET_COMMAND_RESPONSE + }; + } + return base.handleRequest(message); + } + public void AddStatusMessage(RDMStatusMessage statusMessage) + { + int id = 0; + if (this.statusMessages.Count != 0) + id = this.statusMessages.Max(s => s.Key) + 1; + if (this.statusMessages.TryAdd(id, statusMessage)) + { + this.ParentDevice.setParameterValue(ERDM_Parameter.STATUS_MESSAGES, this.statusMessages.Select(sm => sm.Value).ToArray()); + OnPropertyChanged(nameof(StatusMessages)); + } + } + public void ClearStatusMessage(RDMStatusMessage statusMessage) + { + this.statusMessages.Where(s => s.Value.Equals(statusMessage)).ToList().ForEach(s => + { + s.Value.Clear(); + }); + this.ParentDevice.setParameterValue(ERDM_Parameter.STATUS_MESSAGES, this.statusMessages.Select(sm => sm.Value).ToArray()); + OnPropertyChanged(nameof(StatusMessages)); + } + public void RemoveStatusMessage(RDMStatusMessage statusMessage) + { + bool succes = false; + this.statusMessages.Where(s => s.Value.Equals(statusMessage)).ToList().ForEach(s => + { + if (this.statusMessages.TryRemove(s.Key, out _)) + succes = true; + }); + if (succes) + { + this.ParentDevice.setParameterValue(ERDM_Parameter.STATUS_MESSAGES, this.statusMessages.Select(sm => sm.Value).ToArray()); + OnPropertyChanged(nameof(StatusMessages)); + } + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/Module/TagsModule.cs b/RDMSharp/RDM/Device/Module/TagsModule.cs new file mode 100644 index 0000000..0b3c71e --- /dev/null +++ b/RDMSharp/RDM/Device/Module/TagsModule.cs @@ -0,0 +1,309 @@ +using RDMSharp.Metadata; +using System.Collections.Generic; + +namespace RDMSharp.RDM.Device.Module +{ + public sealed class TagsModule : AbstractModule + { + private List tags = new List(); + public IReadOnlyCollection Tags + { + get + { + IReadOnlyCollection tagList = null; + if (this.ParentDevice.GetAllParameterValues().TryGetValue(ERDM_Parameter.LIST_TAGS, out object tags)) + { + if (tags is IReadOnlyCollection _tagList) + tagList = _tagList; + } + return tagList; + } + } + public TagsModule() : base( + "Tags", + ERDM_Parameter.LIST_TAGS, + ERDM_Parameter.ADD_TAG, + ERDM_Parameter.REMOVE_TAG, + ERDM_Parameter.CHECK_TAG, + ERDM_Parameter.CLEAR_TAGS) + { + } + + protected override void OnParentDeviceChanged(AbstractGeneratedRDMDevice device) + { + this.ParentDevice.setParameterValue(ERDM_Parameter.LIST_TAGS, tags.ToArray()); + } + + protected override void ParameterChanged(ERDM_Parameter parameter, object newValue, object index) + { + switch (parameter) + { + case ERDM_Parameter.LIST_TAGS: + OnPropertyChanged(nameof(Tags)); + break; + } + } + public override bool IsHandlingParameter(ERDM_Parameter parameter, ERDM_Command command) + { + switch (parameter) + { + case ERDM_Parameter.LIST_TAGS: + break; + case ERDM_Parameter.ADD_TAG: + case ERDM_Parameter.REMOVE_TAG: + case ERDM_Parameter.CLEAR_TAGS: + case ERDM_Parameter.CHECK_TAG: + return true; // These parameters are handled by this module. + } + return false; // Default case, not handled by this module. + } + + protected override RDMMessage handleRequest(RDMMessage message) + { + switch (message.Parameter) + { + case ERDM_Parameter.ADD_TAG when message.Command is ERDM_Command.SET_COMMAND: + if (message.Value is string tag) + { + if (string.IsNullOrWhiteSpace(tag)) + { + return new RDMMessage(ERDM_NackReason.FORMAT_ERROR) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + } + try + { +#if DEBUG + if (tag.Equals("GeNeRaTeHaRdWaReFaUlT")) + throw new System.Exception("Simulated hardware fault for testing purposes."); +#endif + if (!validateTag(tag)) + { + return new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + } + if (!tags.Contains(tag)) + tags.Add(tag); + this.ParentDevice.setParameterValue(ERDM_Parameter.LIST_TAGS, tags.ToArray()); + return new RDMMessage() + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + } + catch (System.Exception ex) + { + Logger?.LogError(ex); + } + break; + } + return new RDMMessage(ERDM_NackReason.FORMAT_ERROR) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + case ERDM_Parameter.REMOVE_TAG when message.Command is ERDM_Command.SET_COMMAND: + if (message.Value is string tag2) + { + if (string.IsNullOrWhiteSpace(tag2)) + { + return new RDMMessage(ERDM_NackReason.FORMAT_ERROR) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + } + try + { +#if DEBUG + if (tag2.Equals("GeNeRaTeHaRdWaReFaUlT")) + throw new System.Exception("Simulated hardware fault for testing purposes."); +#endif + if (!validateTag(tag2) || !tags.Contains(tag2)) + { + return new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + } + tags.Remove(tag2); + this.ParentDevice.setParameterValue(ERDM_Parameter.LIST_TAGS, tags.ToArray()); + return new RDMMessage() + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + } + catch (System.Exception ex) + { + Logger?.LogError(ex); + } + break; + } + return new RDMMessage(ERDM_NackReason.FORMAT_ERROR) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + + case ERDM_Parameter.CHECK_TAG when message.Command is ERDM_Command.GET_COMMAND: + + if (message.Value is string tag3) + { + if (string.IsNullOrWhiteSpace(tag3)) + { + return new RDMMessage(ERDM_NackReason.FORMAT_ERROR) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.GET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + } + try + { +#if DEBUG + if (tag3.Equals("GeNeRaTeHaRdWaReFaUlT")) + throw new System.Exception("Simulated hardware fault for testing purposes."); +#endif + if (!validateTag(tag3)) + { + return new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.GET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + } + bool tagExists = tags.Contains(tag3); + return new RDMMessage() + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.GET_COMMAND_RESPONSE, + Parameter = message.Parameter, + ParameterData = tagExists ? new byte[] { 0x01 } : new byte[] { 0x00 } + }; + } + catch (System.Exception ex) + { + Logger?.LogError(ex); + } + break; + } + return new RDMMessage(ERDM_NackReason.FORMAT_ERROR) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.GET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + case ERDM_Parameter.CLEAR_TAGS when message.Command is ERDM_Command.SET_COMMAND: + try + { +#if DEBUG + if (message.SourceUID.Equals(new UID(0xeeee, 0xf0f0f0f0))) + throw new System.Exception("Simulated hardware fault for testing purposes."); +#endif + tags.Clear(); + this.ParentDevice.setParameterValue(ERDM_Parameter.LIST_TAGS, tags.ToArray()); + } + catch (System.Exception ex) + { + Logger?.LogError(ex); + break; + } + return new RDMMessage() + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = ERDM_Command.SET_COMMAND_RESPONSE, + Parameter = message.Parameter + }; + case ERDM_Parameter.ADD_TAG: + case ERDM_Parameter.REMOVE_TAG: + case ERDM_Parameter.CHECK_TAG: + case ERDM_Parameter.CLEAR_TAGS: + return new RDMMessage(ERDM_NackReason.UNSUPPORTED_COMMAND_CLASS) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = message.Command | ERDM_Command.RESPONSE, + Parameter = message.Parameter + }; + } + return new RDMMessage(ERDM_NackReason.HARDWARE_FAULT) + { + SourceUID = message.DestUID, + DestUID = message.SourceUID, + Command = message.Command | ERDM_Command.RESPONSE, + Parameter = message.Parameter + }; + } + + public void AddTag(string tag) + { + if (string.IsNullOrWhiteSpace(tag)) + throw new System.ArgumentException("Tag can't be null or whitespace.", nameof(tag)); + if (!validateTag(tag)) + throw new System.ArgumentOutOfRangeException(nameof(tag), "Tag must not exceed 32 characters."); + if (!tags.Contains(tag)) + { + tags.Add(tag); + this.ParentDevice.setParameterValue(ERDM_Parameter.LIST_TAGS, tags.ToArray()); + } + } + public void RemoveTag(string tag) + { + if (string.IsNullOrWhiteSpace(tag)) + throw new System.ArgumentException("Tag can't be null or whitespace.", nameof(tag)); + if (!validateTag(tag)) + throw new System.ArgumentOutOfRangeException(nameof(tag), "Tag must not exceed 32 characters."); + if (tags.Contains(tag)) + { + tags.Remove(tag); + this.ParentDevice.setParameterValue(ERDM_Parameter.LIST_TAGS, tags.ToArray()); + } + } + public bool CheckTag(string tag) + { + if (string.IsNullOrWhiteSpace(tag)) + throw new System.ArgumentException("Tag can't be null or whitespace.", nameof(tag)); + if (!validateTag(tag)) + throw new System.ArgumentOutOfRangeException(nameof(tag), "Tag must not exceed 32 characters."); + return tags.Contains(tag); + } + public void ClearTags() + { + tags.Clear(); + this.ParentDevice.setParameterValue(ERDM_Parameter.LIST_TAGS, tags.ToArray()); + } + private bool validateTag(string tag) + { + return tag.Length <= 32; + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/ParameterMetadata.cs b/RDMSharp/RDM/Device/ParameterMetadata.cs new file mode 100644 index 0000000..6127a03 --- /dev/null +++ b/RDMSharp/RDM/Device/ParameterMetadata.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; + +namespace RDMSharp.RDM.Device; + +public class ParameterMetadata : INotifyPropertyChanged +{ + public readonly ERDM_Parameter Parameter; + + public event PropertyChangedEventHandler PropertyChanged; + + private EQueuedParameterCapabilitiesStatus _queuedCapabilitiesStatus = EQueuedParameterCapabilitiesStatus.Unknown; + public EQueuedParameterCapabilitiesStatus QueuedCapabilitiesStatus + { + get + { + return _queuedCapabilitiesStatus; + } + internal set + { + if (_queuedCapabilitiesStatus == value) + return; + _queuedCapabilitiesStatus = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(QueuedCapabilitiesStatus))); + } + } + + private DateTime _lastUpdated = DateTime.MinValue; + public DateTime LastUpdated + { + get + { + return _lastUpdated; + } + private set + { + if (_lastUpdated == value) + return; + _lastUpdated = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(LastUpdated))); + } + } + + private List peerToPeerProcesses = new List(); + public IReadOnlyCollection PeerToPeerProcesses => peerToPeerProcesses; + + private List requestResponseHistory = new List(); + public IReadOnlyCollection RequestResponseHistory => requestResponseHistory; + + public event EventHandler OnRequestResponseHistoryAdded; + + public ParameterMetadata(ERDM_Parameter parameter) + { + Parameter = parameter; + } + + internal void AddPeerToPeerProcess(PeerToPeerProcess process) + { + process.PropertyChanged += Process_PropertyChanged; + process.OnRequestResponseHistoryAdded += Process_OnRequestResponseHistoryAdded; + peerToPeerProcesses.Add(process); + } + + private void Process_OnRequestResponseHistoryAdded(object sender, RequestResponseHistoryEntry entry) + { + const int maxHistoryEntries = 20; + requestResponseHistory.Add(entry); + + if (requestResponseHistory.Count > maxHistoryEntries) + { + int excessEntries = requestResponseHistory.Count - maxHistoryEntries; + requestResponseHistory.RemoveRange(0, excessEntries); + } + OnRequestResponseHistoryAdded?.Invoke(this, entry); + } + + private void Process_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + PeerToPeerProcess process = sender as PeerToPeerProcess; + switch (e.PropertyName) + { + case nameof(process.State): + switch (process.State) + { + case PeerToPeerProcess.EPeerToPeerProcessState.Finished: + peerToPeerProcesses.Remove(process); + LastUpdated = DateTime.Now; + break; + case PeerToPeerProcess.EPeerToPeerProcessState.Failed: + peerToPeerProcesses.Remove(process); + break; + } + break; + + } + } +} +public enum EQueuedParameterCapabilitiesStatus : byte +{ + Unknown = 0b00000000, + QueuedMessagesParameterSupported = 0b00000010, + Try_1 = 0b00000100, + Try_2 = 0b00001000, + Try_3 = 0b00010000, + Pending = 0b00100000, + Supported = 0b01000000, + NotSupported = 0b10000000, +} \ No newline at end of file diff --git a/RDMSharp/RDM/Device/RDMDeviceModel.cs b/RDMSharp/RDM/Device/RDMDeviceModel.cs index 5e09a6c..f2135c1 100644 --- a/RDMSharp/RDM/Device/RDMDeviceModel.cs +++ b/RDMSharp/RDM/Device/RDMDeviceModel.cs @@ -7,349 +7,348 @@ using System.Threading; using System.Threading.Tasks; -namespace RDMSharp -{ - public sealed class RDMDeviceModel : AbstractRDMCache, IRDMDeviceModel +namespace RDMSharp; + +public sealed class RDMDeviceModel : AbstractRDMCache, IRDMDeviceModel +{ + private static ConcurrentDictionary knownDeviceModels; + public static IReadOnlyCollection KnownDeviceModels => knownDeviceModels.Values.ToList(); + internal static RDMDeviceModel getDeviceModel(UID uid, SubDevice subDevice, RDMDeviceInfo deviceInfo, Func sendRdmFunktion) { - private static ConcurrentDictionary knownDeviceModels; - public static IReadOnlyCollection KnownDeviceModels => knownDeviceModels.Values.ToList(); - internal static RDMDeviceModel getDeviceModel(UID uid, SubDevice subDevice, RDMDeviceInfo deviceInfo, Func sendRdmFunktion) + knownDeviceModels ??= new ConcurrentDictionary(); + var kdm = knownDeviceModels.Values.FirstOrDefault(dm => dm.IsModelOf(uid, subDevice, deviceInfo)); + if (kdm == null) { - knownDeviceModels ??= new ConcurrentDictionary(); - var kdm = knownDeviceModels.Values.FirstOrDefault(dm => dm.IsModelOf(uid, subDevice, deviceInfo)); - if (kdm == null) - { - kdm = new RDMDeviceModel(uid, subDevice, deviceInfo); - knownDeviceModels.TryAdd(kdm.GetHashCode(), kdm); - } + kdm = new RDMDeviceModel(uid, subDevice, deviceInfo); + knownDeviceModels.TryAdd(kdm.GetHashCode(), kdm); + } - return kdm; + return kdm; - } + } - private ConcurrentDictionary knownPersonalityModels = new ConcurrentDictionary(); - public IReadOnlyCollection KnownPersonalityModels => knownPersonalityModels.Values.ToList(); - internal RDMPersonalityModel getPersonalityModel(IRDMRemoteDevice remoteRDMDevice, byte personalityId) + private ConcurrentDictionary knownPersonalityModels = new ConcurrentDictionary(); + public IReadOnlyCollection KnownPersonalityModels => knownPersonalityModels.Values.ToList(); + internal RDMPersonalityModel getPersonalityModel(IRDMRemoteDevice remoteRDMDevice, byte personalityId) + { + try { - try + if (!DeviceInfo.Dmx512CurrentPersonality.HasValue) + return null; + var kpm = knownPersonalityModels.Values.FirstOrDefault(dm => dm.IsModelOf( + remoteRDMDevice.UID, + remoteRDMDevice.DeviceInfo.DeviceModelId, + remoteRDMDevice.DeviceInfo.SoftwareVersionId, + personalityId)); + if (kpm == null) { - if (!DeviceInfo.Dmx512CurrentPersonality.HasValue) - return null; - var kpm = knownPersonalityModels.Values.FirstOrDefault(dm => dm.IsModelOf( - remoteRDMDevice.UID, - remoteRDMDevice.DeviceInfo.DeviceModelId, - remoteRDMDevice.DeviceInfo.SoftwareVersionId, - personalityId)); - if (kpm == null) - { - kpm = new RDMPersonalityModel( - remoteRDMDevice, - personalityId); - knownPersonalityModels.TryAdd(kpm.PersonalityID, kpm); - } - return kpm; + kpm = new RDMPersonalityModel( + remoteRDMDevice, + personalityId); + knownPersonalityModels.TryAdd(kpm.PersonalityID, kpm); } - catch (Exception ex) - { - Logger?.LogError(ex); - } - return null; + return kpm; + } + catch (Exception ex) + { + Logger?.LogError(ex); } + return null; + } - public new bool IsDisposing { get; private set; } - public new bool IsDisposed { get; private set; } + public new bool IsDisposing { get; private set; } + public new bool IsDisposed { get; private set; } - public bool IsInitialized { get; private set; } = false; - public bool IsInitializing { get; private set; } = false; + public bool IsInitialized { get; private set; } = false; + public bool IsInitializing { get; private set; } = false; - public event EventHandler Initialized; - public event PropertyChangedEventHandler PropertyChanged; - public new event EventHandler ParameterValueAdded + public event EventHandler Initialized; + public event PropertyChangedEventHandler PropertyChanged; + public new event EventHandler ParameterValueAdded + { + add { - add - { - base.ParameterValueAdded += value; - } - remove - { - base.ParameterValueAdded -= value; - } - } + base.ParameterValueAdded += value; + } + remove + { + base.ParameterValueAdded -= value; + } + } - public readonly ushort ManufacturerID; - public readonly EManufacturer Manufacturer; + public readonly ushort ManufacturerID; + public readonly EManufacturer Manufacturer; - private UID currentUsedUID; - public UID CurrentUsedUID + private UID currentUsedUID; + public UID CurrentUsedUID + { + get { return currentUsedUID; } + private set { - get { return currentUsedUID; } - private set - { - if (currentUsedUID == value) - return; - currentUsedUID = value; - PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(CurrentUsedUID))); - } - } - private SubDevice currentUsedSubDevice; - public SubDevice CurrentUsedSubDevice + if (currentUsedUID == value) + return; + currentUsedUID = value; + PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(CurrentUsedUID))); + } + } + private SubDevice currentUsedSubDevice; + public SubDevice CurrentUsedSubDevice + { + get { - get - { - return currentUsedSubDevice; - } - private set - { - if (currentUsedSubDevice == value) - return; - currentUsedSubDevice = value; - PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(CurrentUsedSubDevice))); - } + return currentUsedSubDevice; } + private set + { + if (currentUsedSubDevice == value) + return; + currentUsedSubDevice = value; + PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(CurrentUsedSubDevice))); + } + } - public RDMDeviceInfo DeviceInfo + public RDMDeviceInfo DeviceInfo + { + get { return parameterValues.TryGetValue(ERDM_Parameter.DEVICE_INFO, out object value) ? value as RDMDeviceInfo : null; } + private set { - get { return parameterValues.TryGetValue(ERDM_Parameter.DEVICE_INFO, out object value) ? value as RDMDeviceInfo : null; } - private set - { - if (this.DeviceInfo == value) - return; - - 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))); - } + if (this.DeviceInfo == value) + return; + + 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))); } + } - 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)).OrderBy(p => p).ToArray().AsReadOnly(); } - } - public IReadOnlyCollection SupportedBlueprintParameters - { - get { return this.SupportedParameters.Intersect(Constants.BLUEPRINT_MODEL_PARAMETERS).OrderBy(p => p).ToList().AsReadOnly(); } - } - public IReadOnlyCollection SupportedPersonalityBlueprintParameters - { - get { return this.SupportedParameters.Intersect(Constants.BLUEPRINT_MODEL_PERSONALITY_PARAMETERS).OrderBy(p => p).ToList().AsReadOnly(); } - } - public IReadOnlyCollection SupportedNonBlueprintParameters - { - get { return this.SupportedParameters.Except(SupportedBlueprintParameters).Except(SupportedPersonalityBlueprintParameters).OrderBy(p => p).ToList().AsReadOnly(); } - } + 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)).OrderBy(p => p).ToArray().AsReadOnly(); } + } + public IReadOnlyCollection SupportedBlueprintParameters + { + get { return this.SupportedParameters.Intersect(Constants.BLUEPRINT_MODEL_PARAMETERS).OrderBy(p => p).ToList().AsReadOnly(); } + } + public IReadOnlyCollection SupportedPersonalityBlueprintParameters + { + get { return this.SupportedParameters.Intersect(Constants.BLUEPRINT_MODEL_PERSONALITY_PARAMETERS).OrderBy(p => p).ToList().AsReadOnly(); } + } + public IReadOnlyCollection SupportedNonBlueprintParameters + { + get { return this.SupportedParameters.Except(SupportedBlueprintParameters).Except(SupportedPersonalityBlueprintParameters).OrderBy(p => p).ToList().AsReadOnly(); } + } - public IReadOnlyCollection KnownNotSupportedParameters - { - get { return this.supportedParameters.Where(sp => !sp.Value).Select(sp => sp.Key).OrderBy(p => p).ToArray().AsReadOnly(); } - } + public IReadOnlyCollection KnownNotSupportedParameters + { + get { return this.supportedParameters.Where(sp => !sp.Value).Select(sp => sp.Key).OrderBy(p => p).ToArray().AsReadOnly(); } + } - internal RDMDeviceModel(UID uid, SubDevice subdevice, RDMDeviceInfo deviceInfo) - { - DeviceInfo = deviceInfo; - CurrentUsedUID = uid; - CurrentUsedSubDevice = subdevice; - ManufacturerID = uid.ManufacturerID; - Manufacturer = (EManufacturer)uid.ManufacturerID; - this.ParameterValueAdded += RDMDeviceModel_ParameterValueAdded; - } - - private SemaphoreSlim initializeSemaphoreSlim = new SemaphoreSlim(1); - internal async Task Initialize() + internal RDMDeviceModel(UID uid, SubDevice subdevice, RDMDeviceInfo deviceInfo) + { + DeviceInfo = deviceInfo; + CurrentUsedUID = uid; + CurrentUsedSubDevice = subdevice; + ManufacturerID = uid.ManufacturerID; + Manufacturer = (EManufacturer)uid.ManufacturerID; + this.ParameterValueAdded += RDMDeviceModel_ParameterValueAdded; + } + + private SemaphoreSlim initializeSemaphoreSlim = new SemaphoreSlim(1); + internal async Task Initialize() + { + if (IsInitialized) + return; + if (initializeSemaphoreSlim.CurrentCount == 0) + return; + IsInitializing = true; + + await initializeSemaphoreSlim.WaitAsync(); + try { - if (IsInitialized) - return; - if (initializeSemaphoreSlim.CurrentCount == 0) - return; - IsInitializing = true; - - await initializeSemaphoreSlim.WaitAsync(); - try - { - await requestSupportedParameters(); - await requestBlueprintParameters(); - //await requestPersonalityBlueprintParameters(); + await requestSupportedParameters(); + await requestBlueprintParameters(); + //await requestPersonalityBlueprintParameters(); - IsInitialized = true; - } - finally - { - initializeSemaphoreSlim.Release(); - IsInitializing = false; - } - Initialized?.Invoke(this, EventArgs.Empty); + IsInitialized = true; } + finally + { + initializeSemaphoreSlim.Release(); + IsInitializing = false; + } + Initialized?.Invoke(this, EventArgs.Empty); + } - #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); + #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 (!ptpProcess.ResponsePayloadObject.IsUnset) - updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(parameterBag.PID), ptpProcess.ResponsePayloadObject); + if (!ptpProcess.ResponsePayloadObject.IsUnset) + updateParameterValuesDataTreeBranch(new ParameterDataCacheBag(parameterBag.PID), ptpProcess.ResponsePayloadObject); - if (ptpProcess.ResponsePayloadObject.ParsedObject is ERDM_Parameter[] parameters) + if (ptpProcess.ResponsePayloadObject.ParsedObject is ERDM_Parameter[] parameters) + { + foreach (var para in parameters) { - foreach (var para in parameters) - { - if (!this.supportedParameters.TryGetValue(para, out _)) - supportedParameters.TryAdd(para, true); - } - if (DeviceInfo.Dmx512StartAddress.HasValue && DeviceInfo.Dmx512StartAddress >= 1 && DeviceInfo.Dmx512StartAddress.Value <= 512) // Remote Device not send DMX_START_ADDRESS Parameter but uses it! - supportedParameters.TryAdd(ERDM_Parameter.DMX_START_ADDRESS, true); + if (!this.supportedParameters.TryGetValue(para, out _)) + supportedParameters.TryAdd(para, true); + } + if (DeviceInfo.Dmx512StartAddress.HasValue && DeviceInfo.Dmx512StartAddress >= 1 && DeviceInfo.Dmx512StartAddress.Value <= 512) // Remote Device not send DMX_START_ADDRESS Parameter but uses it! + supportedParameters.TryAdd(ERDM_Parameter.DMX_START_ADDRESS, true); - if (DeviceInfo.Dmx512CurrentPersonality.HasValue) // Remote Device not send DMX_PERSONALITY Parameter but uses it! - supportedParameters.TryAdd(ERDM_Parameter.DMX_PERSONALITY, true); + if (DeviceInfo.Dmx512CurrentPersonality.HasValue) // Remote Device not send DMX_PERSONALITY Parameter but uses it! + supportedParameters.TryAdd(ERDM_Parameter.DMX_PERSONALITY, true); - if (!this.supportedParameters.ContainsKey(ERDM_Parameter.PARAMETER_DESCRIPTION) && this.supportedParameters.Any(p=> ((ushort)p.Key) >= 0x8000 && ((ushort)p.Key) <= 0xFFDF)) // Remote Device not send PARAMETER_DESCRIPTION Parameter but has Manufacture speific Parameters it! - this.supportedParameters.TryAdd(ERDM_Parameter.PARAMETER_DESCRIPTION, true); + if (!this.supportedParameters.ContainsKey(ERDM_Parameter.PARAMETER_DESCRIPTION) && this.supportedParameters.Any(p => ((ushort)p.Key) >= 0x8000 && ((ushort)p.Key) <= 0xFFDF)) // Remote Device not send PARAMETER_DESCRIPTION Parameter but has Manufacture speific Parameters it! + this.supportedParameters.TryAdd(ERDM_Parameter.PARAMETER_DESCRIPTION, true); - if (!this.supportedParameters.ContainsKey(ERDM_Parameter.IDENTIFY_DEVICE)) //Test it if the device supports Identify Device Parameter, if not it will be labled as not supported later on - this.supportedParameters.TryAdd(ERDM_Parameter.IDENTIFY_DEVICE, true); + if (!this.supportedParameters.ContainsKey(ERDM_Parameter.IDENTIFY_DEVICE)) //Test it if the device supports Identify Device Parameter, if not it will be labled as not supported later on + this.supportedParameters.TryAdd(ERDM_Parameter.IDENTIFY_DEVICE, true); - if (!this.supportedParameters.ContainsKey(ERDM_Parameter.SOFTWARE_VERSION_LABEL))//Test it if the device supports Software Version Lable Device Parameter, if not it will be labled as not supported later on - this.supportedParameters.TryAdd(ERDM_Parameter.SOFTWARE_VERSION_LABEL, true); + if (!this.supportedParameters.ContainsKey(ERDM_Parameter.SOFTWARE_VERSION_LABEL))//Test it if the device supports Software Version Lable Device Parameter, if not it will be labled as not supported later on + this.supportedParameters.TryAdd(ERDM_Parameter.SOFTWARE_VERSION_LABEL, true); - if (!this.supportedParameters.ContainsKey(ERDM_Parameter.FACTORY_DEFAULTS))//Test it if the device supports Factory Defaults Device Parameter, if not it will be labled as not supported later on - this.supportedParameters.TryAdd(ERDM_Parameter.FACTORY_DEFAULTS, true); + if (!this.supportedParameters.ContainsKey(ERDM_Parameter.FACTORY_DEFAULTS))//Test it if the device supports Factory Defaults Device Parameter, if not it will be labled as not supported later on + this.supportedParameters.TryAdd(ERDM_Parameter.FACTORY_DEFAULTS, true); - if(this.supportedParameters.Any(p=>((ushort)p.Key)>0x9000 && ((ushort)p.Key) <= 0x900D)) - this.supportedParameters.TryAdd(ERDM_Parameter.ENDPOINT_LIST, true); - } - await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenRequests); + if (this.supportedParameters.Any(p => ((ushort)p.Key) > 0x9000 && ((ushort)p.Key) <= 0x900D)) + this.supportedParameters.TryAdd(ERDM_Parameter.ENDPOINT_LIST, true); } + await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenRequests); + } - private async Task requestBlueprintParameters() + private async Task requestBlueprintParameters() + { + var parameters = this.SupportedBlueprintParameters.OrderBy(p => (ushort)p).ToList(); + foreach (ERDM_Parameter parameter in parameters) { - var parameters = this.SupportedBlueprintParameters.OrderBy(p => (ushort)p).ToList(); - foreach (ERDM_Parameter parameter in parameters) + if (parameter == ERDM_Parameter.SUPPORTED_PARAMETERS) + continue; + ParameterBag parameterBag = new ParameterBag(parameter, ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId); + var define = MetadataFactory.GetDefine(parameterBag); + if (define.GetRequest.HasValue) { - if (parameter == ERDM_Parameter.SUPPORTED_PARAMETERS) - continue; - 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 requestGetParameterWithEmptyPayload(parameterBag, define, CurrentUsedUID, CurrentUsedSubDevice); - else if (parameter == ERDM_Parameter.PARAMETER_DESCRIPTION) - foreach (var pid in this.supportedParameters.Where(p => (ushort)p.Key >= 0x8000 && (ushort)p.Key <= 0xFFDF).Select(p => (ushort)p.Key)) - await requestGetParameterWithPayload(parameterBag, define, CurrentUsedUID, CurrentUsedSubDevice, pid); - else - await requestGetParameterWithPayload(parameterBag, define, CurrentUsedUID, CurrentUsedSubDevice); - } - await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenRequests); + if (define.GetRequest.Value.GetIsEmpty()) + await requestGetParameterWithEmptyPayload(parameterBag, define, CurrentUsedUID, CurrentUsedSubDevice); + else if (parameter == ERDM_Parameter.PARAMETER_DESCRIPTION) + foreach (var pid in this.supportedParameters.Where(p => (ushort)p.Key >= 0x8000 && (ushort)p.Key <= 0xFFDF).Select(p => (ushort)p.Key)) + await requestGetParameterWithPayload(parameterBag, define, CurrentUsedUID, CurrentUsedSubDevice, pid); + else + await requestGetParameterWithPayload(parameterBag, define, CurrentUsedUID, CurrentUsedSubDevice); } + await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenRequests); } - #endregion + } + #endregion - public bool IsModelOf(UID uid, SubDevice subDevice, RDMDeviceInfo other) - { - var deviceInfo = this.DeviceInfo; - if (this.ManufacturerID != uid.ManufacturerID) - return false; - if (this.CurrentUsedSubDevice != subDevice) - return false; - if (deviceInfo.DeviceModelId != other.DeviceModelId) - return false; - if (deviceInfo.RdmProtocolVersionMajor != other.RdmProtocolVersionMajor) - return false; - if (deviceInfo.RdmProtocolVersionMinor != other.RdmProtocolVersionMinor) - return false; - if (deviceInfo.SoftwareVersionId != other.SoftwareVersionId) - return false; - if (deviceInfo.Dmx512NumberOfPersonalities != other.Dmx512NumberOfPersonalities) - return false; - if (deviceInfo.ProductCategoryCoarse != other.ProductCategoryCoarse) - return false; - if (deviceInfo.ProductCategoryFine != other.ProductCategoryFine) - return false; - if (deviceInfo.SensorCount != other.SensorCount) - return false; + public bool IsModelOf(UID uid, SubDevice subDevice, RDMDeviceInfo other) + { + var deviceInfo = this.DeviceInfo; + if (this.ManufacturerID != uid.ManufacturerID) + return false; + if (this.CurrentUsedSubDevice != subDevice) + return false; + if (deviceInfo.DeviceModelId != other.DeviceModelId) + return false; + if (deviceInfo.RdmProtocolVersionMajor != other.RdmProtocolVersionMajor) + return false; + if (deviceInfo.RdmProtocolVersionMinor != other.RdmProtocolVersionMinor) + return false; + if (deviceInfo.SoftwareVersionId != other.SoftwareVersionId) + return false; + if (deviceInfo.Dmx512NumberOfPersonalities != other.Dmx512NumberOfPersonalities) + return false; + if (deviceInfo.ProductCategoryCoarse != other.ProductCategoryCoarse) + return false; + if (deviceInfo.ProductCategoryFine != other.ProductCategoryFine) + return false; + if (deviceInfo.SensorCount != other.SensorCount) + return false; - return true; - } - protected sealed override Task OnResponseMessage(RDMMessage rdmMessage) - { - if (rdmMessage.ResponseType == ERDM_ResponseType.NACK_REASON) - handleNACKReason(rdmMessage); - return base.OnResponseMessage(rdmMessage); - } + return true; + } + protected sealed override Task OnResponseMessage(RDMMessage rdmMessage) + { + if (rdmMessage.ResponseType == ERDM_ResponseType.NACK_REASON) + handleNACKReason(rdmMessage); + return base.OnResponseMessage(rdmMessage); + } - internal bool handleNACKReason(RDMMessage rdmMessage) + internal bool handleNACKReason(RDMMessage rdmMessage) + { + if (rdmMessage.NackReason == ERDM_NackReason.FORMAT_ERROR || rdmMessage.NackReason == ERDM_NackReason.UNKNOWN_PID) { - if (rdmMessage.NackReason.Contains(ERDM_NackReason.ACTION_NOT_SUPPORTED) || rdmMessage.NackReason.Contains(ERDM_NackReason.UNKNOWN_PID)) - { - AddParameterToKnownNotSupportedParameters(rdmMessage.Parameter); - return false; - } - return true; + AddParameterToKnownNotSupportedParameters(rdmMessage.Parameter); + return false; } + return true; + } - internal void AddParameterToKnownNotSupportedParameters(ERDM_Parameter parameter) - { - this.supportedParameters.AddOrUpdate(parameter, false, (x, y) => false); - } + internal void AddParameterToKnownNotSupportedParameters(ERDM_Parameter parameter) + { + this.supportedParameters.AddOrUpdate(parameter, false, (x, y) => false); + } - private void RDMDeviceModel_ParameterValueAdded(object sender, ParameterValueAddedEventArgs e) + private void RDMDeviceModel_ParameterValueAdded(object sender, ParameterValueAddedEventArgs e) + { + if (e.Parameter == ERDM_Parameter.PARAMETER_DESCRIPTION) { - if (e.Parameter == ERDM_Parameter.PARAMETER_DESCRIPTION) - { - if (e.Value is not RDMParameterDescription pd) - return; + if (e.Value is not RDMParameterDescription pd) + return; - var define = MetadataFactory.GetDefine(new ParameterBag((ERDM_Parameter)pd.ParameterId, this.CurrentUsedUID.ManufacturerID, this.DeviceInfo.DeviceModelId, this.DeviceInfo.SoftwareVersionId)); - if (define is null) - MetadataFactory.AddDefineFromParameterDescription(this.CurrentUsedUID, this.CurrentUsedSubDevice, this.DeviceInfo, pd); - } + var define = MetadataFactory.GetDefine(new ParameterBag((ERDM_Parameter)pd.ParameterId, this.CurrentUsedUID.ManufacturerID, this.DeviceInfo.DeviceModelId, this.DeviceInfo.SoftwareVersionId)); + if (define is null) + MetadataFactory.AddDefineFromParameterDescription(this.CurrentUsedUID, this.CurrentUsedSubDevice, this.DeviceInfo, pd); } + } - public new void Dispose() - { - if (this.IsDisposed || this.IsDisposing) - return; + public new void Dispose() + { + if (this.IsDisposed || this.IsDisposing) + return; - this.IsDisposing = true; - this.PropertyChanged = null; - this.Initialized = null; + this.IsDisposing = true; + this.PropertyChanged = null; + this.Initialized = null; - this.supportedParameters = null; - base.Dispose(); + this.supportedParameters = null; + base.Dispose(); - this.IsDisposed = true; - this.IsDisposing = false; - } + this.IsDisposed = true; + this.IsDisposing = false; + } - public IReadOnlyCollection GetSensorDefinitions() + public IReadOnlyCollection GetSensorDefinitions() + { + try { - try - { - if (!parameterValues.TryGetValue(ERDM_Parameter.SENSOR_DEFINITION, out object value)) - return Array.Empty(); - else - { - if (value is ConcurrentDictionary cd) - return cd.Values.Cast().ToArray(); - return value as RDMSensorDefinition[]; - } - } - catch + if (!parameterValues.TryGetValue(ERDM_Parameter.SENSOR_DEFINITION, out object value)) + return Array.Empty(); + else { - + if (value is ConcurrentDictionary cd) + return cd.Values.Cast().ToArray(); + return value as RDMSensorDefinition[]; } - return Array.Empty(); } - - public override string ToString() + catch { - return $"{Enum.GetName(typeof(EManufacturer), Manufacturer)}"; + } - } + return Array.Empty(); + } + + public override string ToString() + { + return $"{Enum.GetName(typeof(EManufacturer), Manufacturer)}"; + } } \ No newline at end of file diff --git a/RDMSharp/RDM/Device/RDMPersonalityModel.cs b/RDMSharp/RDM/Device/RDMPersonalityModel.cs index 50868de..708e69c 100644 --- a/RDMSharp/RDM/Device/RDMPersonalityModel.cs +++ b/RDMSharp/RDM/Device/RDMPersonalityModel.cs @@ -7,195 +7,195 @@ using System.Threading; using System.Threading.Tasks; -namespace RDMSharp +namespace RDMSharp; + +public sealed class RDMPersonalityModel : AbstractRDMCache { - public sealed class RDMPersonalityModel : AbstractRDMCache - { - public event PropertyChangedEventHandler PropertyChanged; - public event EventHandler SlotAdded; - public event EventHandler Initialized; + public event PropertyChangedEventHandler PropertyChanged; + public event EventHandler SlotAdded; + public event EventHandler Initialized; - public readonly ushort ManufacturerID; - public readonly EManufacturer Manufacturer; + public readonly ushort ManufacturerID; + public readonly EManufacturer Manufacturer; - public readonly ushort DeviceModelID; - public bool IsInitialized { get; private set; } = false; - public bool IsInitializing { get; private set; } = false; + public readonly ushort DeviceModelID; + public bool IsInitialized { get; private set; } = false; + public bool IsInitializing { get; private set; } = false; - //Id given from PID DMX_PERSONALITY = 0x00E0 & DMX_PERSONALITY_DESCRIPTION E1.20 - public byte PersonalityID { get; private set; } - public uint SoftwareVersionID { get; private set; } + //Id given from PID DMX_PERSONALITY = 0x00E0 & DMX_PERSONALITY_DESCRIPTION E1.20 + public byte PersonalityID { get; private set; } + public uint SoftwareVersionID { get; private set; } - //Id given from PID DMX_PERSONALITY_ID E1.37-5 - 2024 - public ushort? MajorPersonalityID { get; private set; } - public ushort? MinorPersonalityID { get; private set; } + //Id given from PID DMX_PERSONALITY_ID E1.37-5 - 2024 + public ushort? MajorPersonalityID { get; private set; } + public ushort? MinorPersonalityID { get; private set; } - private SubDevice subDevice; - public SubDevice SubDevice + private SubDevice subDevice; + public SubDevice SubDevice + { + get { - get - { - return subDevice; - } - private set - { - if (subDevice == value) - return; - subDevice = value; - PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(SubDevice))); - } + return subDevice; } + private set + { + if (subDevice == value) + return; + subDevice = value; + PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(SubDevice))); + } + } - private ConcurrentDictionary slots = new ConcurrentDictionary(); - public IReadOnlyDictionary Slots => slots.AsReadOnly(); - public readonly IReadOnlyCollection SupportedPersonalityBlueprintParameters; + private ConcurrentDictionary slots = new ConcurrentDictionary(); + public IReadOnlyDictionary Slots => slots.AsReadOnly(); + public readonly IReadOnlyCollection SupportedPersonalityBlueprintParameters; - private UID currentUsedUid; + private UID currentUsedUid; - public string Description { get; private set; } - public ushort SlotCount { get; private set; } + public string Description { get; private set; } + public ushort SlotCount { get; private set; } - internal RDMPersonalityModel(IRDMRemoteDevice remoteRDMDevice, byte personalityId) + internal RDMPersonalityModel(IRDMRemoteDevice remoteRDMDevice, byte personalityId) + { + currentUsedUid = remoteRDMDevice.UID; + SubDevice = remoteRDMDevice.Subdevice; + ManufacturerID = remoteRDMDevice.UID.ManufacturerID; + Manufacturer = (EManufacturer)ManufacturerID; + DeviceModelID = remoteRDMDevice.DeviceInfo.DeviceModelId; + SoftwareVersionID = remoteRDMDevice.DeviceInfo.SoftwareVersionId; + PersonalityID = personalityId; + this.ParameterValueAdded += RDMDeviceModel_ParameterValueAdded; + if (remoteRDMDevice is AbstractRemoteRDMDevice rd) { - currentUsedUid = remoteRDMDevice.UID; - SubDevice = remoteRDMDevice.Subdevice; - ManufacturerID = remoteRDMDevice.UID.ManufacturerID; - Manufacturer = (EManufacturer)ManufacturerID; - DeviceModelID = remoteRDMDevice.DeviceInfo.DeviceModelId; - SoftwareVersionID = remoteRDMDevice.DeviceInfo.SoftwareVersionId; - PersonalityID = personalityId; - this.ParameterValueAdded += RDMDeviceModel_ParameterValueAdded; - if (remoteRDMDevice is AbstractRemoteRDMDevice rd) + SupportedPersonalityBlueprintParameters = rd.DeviceModel.SupportedPersonalityBlueprintParameters; + if (remoteRDMDevice.ParameterValues.TryGetValue(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION, out object obj) && obj is ConcurrentDictionary dict) { - SupportedPersonalityBlueprintParameters = rd.DeviceModel.SupportedPersonalityBlueprintParameters; - if (remoteRDMDevice.ParameterValues.TryGetValue(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION, out object obj) && obj is ConcurrentDictionary dict) + if (dict.TryGetValue(personalityId, out object disc) && disc is RDMDMXPersonalityDescription personalityDescription) { - if (dict.TryGetValue(personalityId, out object disc) && disc is RDMDMXPersonalityDescription personalityDescription) - { - this.Description = personalityDescription.Description; - SlotCount = personalityDescription.Slots; - var rpl=DataTreeBranch.FromObject(personalityDescription, null, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION); - updateParameterValuesDependeciePropertyBag(ERDM_Parameter.SLOT_DESCRIPTION, rpl); - } + this.Description = personalityDescription.Description; + SlotCount = personalityDescription.Slots; + var rpl = DataTreeBranch.FromObject(personalityDescription, null, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION); + updateParameterValuesDependeciePropertyBag(ERDM_Parameter.SLOT_DESCRIPTION, rpl); } } } - private SemaphoreSlim initializeSemaphoreSlim = new SemaphoreSlim(1); - internal async Task Initialize() + } + private SemaphoreSlim initializeSemaphoreSlim = new SemaphoreSlim(1); + internal async Task Initialize() + { + if (IsInitialized) + return; + if (initializeSemaphoreSlim.CurrentCount == 0) + return; + IsInitializing = true; + + await initializeSemaphoreSlim.WaitAsync(); + try { - if (IsInitialized) - return; - if (initializeSemaphoreSlim.CurrentCount == 0) - return; - IsInitializing = true; - - await initializeSemaphoreSlim.WaitAsync(); - try - { - await requestPersonalityBlueprintParameters(); + await requestPersonalityBlueprintParameters(); - IsInitialized = true; - } - finally - { - initializeSemaphoreSlim.Release(); - IsInitializing = false; - } - Initialized?.Invoke(this, EventArgs.Empty); + IsInitialized = true; } + finally + { + initializeSemaphoreSlim.Release(); + IsInitializing = false; + } + Initialized?.Invoke(this, EventArgs.Empty); + } - internal async Task requestPersonalityBlueprintParameters() + internal async Task requestPersonalityBlueprintParameters() + { + try { - try + foreach (ERDM_Parameter parameter in this.SupportedPersonalityBlueprintParameters) { - foreach (ERDM_Parameter parameter in this.SupportedPersonalityBlueprintParameters) + tryAddParameterMetadata(parameter); + ParameterBag parameterBag = new ParameterBag(parameter, this.ManufacturerID, this.DeviceModelID, this.SoftwareVersionID); + var define = MetadataFactory.GetDefine(parameterBag); + if (define.GetRequest.HasValue) { - ParameterBag parameterBag = new ParameterBag(parameter, this.ManufacturerID, this.DeviceModelID, this.SoftwareVersionID); - var define = MetadataFactory.GetDefine(parameterBag); - if (define.GetRequest.HasValue) - { - if (define.GetRequest.Value.GetIsEmpty()) - await requestGetParameterWithEmptyPayload(parameterBag, define, currentUsedUid, SubDevice); - else - await requestGetParameterWithPayload(parameterBag, define, currentUsedUid, SubDevice); - } - await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenRequests); + if (define.GetRequest.Value.GetIsEmpty()) + await requestGetParameterWithEmptyPayload(parameterBag, define, currentUsedUid, SubDevice); + else + await requestGetParameterWithPayload(parameterBag, define, currentUsedUid, SubDevice); } - } - catch (Exception ex) - { - Logger?.LogError(ex); + await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenRequests); } } - internal void RDMDeviceModel_ParameterValueAdded(object sender, ParameterValueAddedEventArgs e) + catch (Exception ex) { - if (!Constants.BLUEPRINT_MODEL_PERSONALITY_PARAMETERS.Contains(e.Parameter)) - return; - - //var cache = sender as AbstractRDMCache; - //var bag = new ParameterDataCacheBag(e.Parameter, e.Index); - //cache.parameterValuesDataTreeBranch.TryGetValue(bag, out var value); - //updateParameterValuesDataTreeBranch(bag, value); + Logger?.LogError(ex); + } + } + internal void RDMDeviceModel_ParameterValueAdded(object sender, ParameterValueAddedEventArgs e) + { + if (!Constants.BLUEPRINT_MODEL_PERSONALITY_PARAMETERS.Contains(e.Parameter)) + return; - if (e.Value is RDMSlotInfo[] slotInfos) - { - foreach (var slotInfo in slotInfos) - getOrCreate(slotInfo.SlotOffset).UpdateSlotInfo(slotInfo); - return; - } - if (e.Value is RDMDefaultSlotValue[] defaultSlotValues) - { - foreach (var defaultSlotValue in defaultSlotValues) - getOrCreate(defaultSlotValue.SlotOffset).UpdateSlotDefaultValue(defaultSlotValue); - return; - } - if (e.Value is RDMSlotDescription slotDescription) - { - var slot = getOrCreate(Convert.ToUInt16(e.Index)); - if (slot.SlotId == slotDescription.SlotId) - slot.UpdateSlotDescription(slotDescription); - } + //var cache = sender as AbstractRDMCache; + //var bag = new ParameterDataCacheBag(e.Parameter, e.Index); + //cache.parameterValuesDataTreeBranch.TryGetValue(bag, out var value); + //updateParameterValuesDataTreeBranch(bag, value); - Slot getOrCreate(ushort id) - { - if (!slots.TryGetValue(id, out Slot slot1)) - { - slot1 = new Slot(id); - if (slots.TryAdd(id, slot1)) - SlotAdded?.InvokeFailSafe(this, slot1); - } - return slot1; - } + if (e.Value is RDMSlotInfo[] slotInfos) + { + foreach (var slotInfo in slotInfos) + getOrCreate(slotInfo.SlotOffset).UpdateSlotInfo(slotInfo); + return; } - - public bool IsModelOf(UID uid, ushort deviceModelID, uint softwareVersionID, byte personalityID) + if (e.Value is RDMDefaultSlotValue[] defaultSlotValues) { - if (this.ManufacturerID != uid.ManufacturerID) - return false; - if (this.DeviceModelID != deviceModelID) - return false; - if (this.SoftwareVersionID != softwareVersionID) - return false; - if (this.PersonalityID != personalityID) - return false; - - return true; + foreach (var defaultSlotValue in defaultSlotValues) + getOrCreate(defaultSlotValue.SlotOffset).UpdateSlotDefaultValue(defaultSlotValue); + return; } - public bool IsModelOf(UID uid, ushort majorPersonalityID, ushort minorPersonalityID) + if (e.Value is RDMSlotDescription slotDescription) { - if (this.ManufacturerID != uid.ManufacturerID) - return false; - if (this.MajorPersonalityID != majorPersonalityID) - return false; - if (this.MinorPersonalityID != minorPersonalityID) - return false; - - return true; + var slot = getOrCreate(Convert.ToUInt16(e.Index)); + if (slot.SlotId == slotDescription.SlotId) + slot.UpdateSlotDescription(slotDescription); } - public override string ToString() + Slot getOrCreate(ushort id) { - return $"[{PersonalityID}] {Enum.GetName(typeof(EManufacturer), Manufacturer)}"; + if (!slots.TryGetValue(id, out Slot slot1)) + { + slot1 = new Slot(id); + if (slots.TryAdd(id, slot1)) + SlotAdded?.InvokeFailSafe(this, slot1); + } + return slot1; } } + + public bool IsModelOf(UID uid, ushort deviceModelID, uint softwareVersionID, byte personalityID) + { + if (this.ManufacturerID != uid.ManufacturerID) + return false; + if (this.DeviceModelID != deviceModelID) + return false; + if (this.SoftwareVersionID != softwareVersionID) + return false; + if (this.PersonalityID != personalityID) + return false; + + return true; + } + public bool IsModelOf(UID uid, ushort majorPersonalityID, ushort minorPersonalityID) + { + if (this.ManufacturerID != uid.ManufacturerID) + return false; + if (this.MajorPersonalityID != majorPersonalityID) + return false; + if (this.MinorPersonalityID != minorPersonalityID) + return false; + + return true; + } + + public override string ToString() + { + return $"[{PersonalityID}] {Enum.GetName(typeof(EManufacturer), Manufacturer)}"; + } } \ No newline at end of file diff --git a/RDMSharp/RDM/Enum/EARP_HardwareTypes.cs b/RDMSharp/RDM/Enum/EARP_HardwareTypes.cs new file mode 100644 index 0000000..908d415 --- /dev/null +++ b/RDMSharp/RDM/Enum/EARP_HardwareTypes.cs @@ -0,0 +1,131 @@ +namespace RDMSharp +{ + public enum EARP_HardwareTypes : ushort + { + /// Reserved (RFC5494) + Reserved = 0, + + /// Ethernet (10Mb) [Jon Postel] + Ethernet = 1, + + /// Experimental Ethernet (3Mb) [Jon Postel] + ExperimentalEthernet = 2, + + /// Amateur Radio AX.25 [Philip Koch] + AmateurRadioAX25 = 3, + + /// Proteon ProNET Token Ring [Avri Doria] + ProteonProNetTokenRing = 4, + + /// Chaos [Gill Pratt] + Chaos = 5, + + /// IEEE 802 Networks [Jon Postel] + IEEE802 = 6, + + /// ARCNET (RFC1201) + Arcnet = 7, + + /// Hyperchannel [Jon Postel] + Hyperchannel = 8, + + /// Lanstar [Tom Unger] + Lanstar = 9, + + /// Autonet Short Address [Mike Burrows] + AutonetShortAddress = 10, + + /// LocalTalk [Joyce K. Reynolds] + LocalTalk = 11, + + /// LocalNet (IBM PCNet or SYTEK LocalNET) [Joseph Murdock] + LocalNet = 12, + + /// Ultra link [Rajiv Dhingra] + UltraLink = 13, + + /// SMDS [George Clapp] + SMDS = 14, + + /// Frame Relay [Andy Malis] + FrameRelay = 15, + + /// Asynchronous Transmission Mode (ATM) [JXB2] + ATM1 = 16, + + /// HDLC [Jon Postel] + HDLC = 17, + + /// Fibre Channel (RFC4338) + FibreChannel = 18, + + /// Asynchronous Transmission Mode (ATM) (RFC2225) + ATM2 = 19, + + /// Serial Line [Jon Postel] + SerialLine = 20, + + /// Asynchronous Transmission Mode (ATM) [Mike Burrows] + ATM3 = 21, + + /// MIL-STD-188-220 [Herb Jensen] + MILSTD188220 = 22, + + /// Metricom [Jonathan Stone] + Metricom = 23, + + /// IEEE 1394.1995 [Myron Hattig] + IEEE1394 = 24, + + /// MAPOS [Mitsuru Maruyama] (RFC2176) + MAPOS = 25, + + /// Twinaxial [Marion Pitts] + Twinaxial = 26, + + /// EUI-64 [Kenji Fujisawa] + EUI64 = 27, + + /// HIPARP [Jean Michel Pittet] + HIPARP = 28, + + /// IP and ARP over ISO 7816-3 [Scott Guthery] + IPoverISO78163 = 29, + + /// ARPSec [Jerome Etienne] + ARPSec = 30, + + /// IPsec tunnel (RFC3456) + IPsecTunnel = 31, + + /// InfiniBand (RFC4391) + InfiniBand = 32, + + /// TIA-102 Project 25 Common Air Interface (CAI) [Jeff Anderson, TIA TR-8.5] + TIA102CAI = 33, + + /// Wiegand Interface [Scott Guthery] + WiegandInterface = 34, + + /// Pure IP [Inaky Perez-Gonzalez] + PureIP = 35, + + /// HW_EXP1 (RFC5494) + HW_EXP1 = 36, + + /// HFI [Tseng-Hui Lin] + HFI = 37, + + /// Unified Bus (UB) [Wei Pan] + UnifiedBus = 38, + + /// HW_EXP2 (RFC5494) + HW_EXP2 = 256, + + /// AEthernet [Geoffroy Gramaize] + AEthernet = 257, + + /// Reserved (RFC5494) + Reserved65535 = 65535 + } +} diff --git a/RDMSharp/RDM/Enum/ERDM_ControllerFlags.cs b/RDMSharp/RDM/Enum/ERDM_ControllerFlags.cs new file mode 100644 index 0000000..2b97397 --- /dev/null +++ b/RDMSharp/RDM/Enum/ERDM_ControllerFlags.cs @@ -0,0 +1,11 @@ +using System; + +namespace RDMSharp; + +[Flags] +public enum ERDM_ControllerFlags : byte +{ + None = 0b00000001, + Unicode = 0b00000001, + HiResAckTimerSupport = 0b00000010, +} \ No newline at end of file diff --git a/RDMSharp/RDM/Interface.cs b/RDMSharp/RDM/Interface.cs new file mode 100644 index 0000000..18b2455 --- /dev/null +++ b/RDMSharp/RDM/Interface.cs @@ -0,0 +1,295 @@ +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Text; + +[assembly: InternalsVisibleTo("RDMSharpTests")] +namespace RDMSharp +{ + public class Interface : INotifyPropertyChanged, IEquatable + { + public event PropertyChangedEventHandler PropertyChanged; + public event EventHandler CurrentIPChanged; + public event EventHandler StaticIPChanged; + + public readonly uint InterfaceId; + + private string lable; + public string Lable + { + get { return lable; } + private set + { + if (lable == value) + return; + + lable = value; + this.PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(Lable))); + } + } + + private ERDM_DHCPStatusMode currentIP_DHCPStatus; + public ERDM_DHCPStatusMode CurrentIP_DHCPStatus + { + get { return currentIP_DHCPStatus; } + private set + { + if (currentIP_DHCPStatus == value) + return; + currentIP_DHCPStatus = value; + this.PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(CurrentIP_DHCPStatus))); + } + } + + private IPv4Address currentIP; + public IPv4Address CurrentIP + { + get { return currentIP; } + private set + { + if (currentIP == value) + return; + + currentIP = value; + this.PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(CurrentIP))); + } + } + + private byte currentSubnetMask; + public byte CurrentSubnetMask + { + get { return currentSubnetMask; } + private set + { + if (currentSubnetMask == value) + return; + + currentSubnetMask = value; + this.PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(CurrentSubnetMask))); + } + } + private IPv4Address staticIP; + public IPv4Address StaticIP + { + get { return staticIP; } + private set + { + if (staticIP == value) + return; + + staticIP = value; + this.PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(StaticIP))); + if (!dhcp) + { + currentIP_DHCPStatus = ERDM_DHCPStatusMode.INACTIVE; + CurrentIP = staticIP; + } + } + } + + private byte staticSubnetMask; + public byte StaticSubnetMask + { + get { return staticSubnetMask; } + private set + { + if (staticSubnetMask == value) + return; + + staticSubnetMask = value; + this.PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(StaticSubnetMask))); + if (!dhcp) + { + currentIP_DHCPStatus = ERDM_DHCPStatusMode.INACTIVE; + CurrentSubnetMask = staticSubnetMask; + } + } + } + + public readonly IPv4Address DefaultIP; + public readonly byte DefaultSubnetMask; + + private MACAddress macAddress; + public MACAddress MACAddress + { + get { return macAddress; } + private set + { + if (macAddress == value) + return; + + macAddress = value; + this.PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(MACAddress))); + } + } + + private bool dhcp; + public bool DHCP + { + get { return dhcp; } + set + { + if (dhcp == value) + return; + + dhcp = value; + if (!value) + { + CurrentIP = StaticIP; + CurrentSubnetMask = StaticSubnetMask; + } + this.PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(DHCP))); + } + } + private bool zeroConf; + public bool ZeroConf + { + get { return zeroConf; } + set + { + if (zeroConf == value) + return; + + zeroConf = value; + this.PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(ZeroConf))); + } + } + + private EARP_HardwareTypes hardwareType; + public EARP_HardwareTypes HardwareType + { + get { return hardwareType; } + private set + { + if (hardwareType == value) + return; + + hardwareType = value; + this.PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(HardwareType))); + } + } + + public Interface(in byte interfaceId) + { + this.InterfaceId = interfaceId; + } + internal protected Interface(in byte interfaceId, + in string lable, + in IPv4Address zeroconfIp, + in byte zeroconfSubnetMask, + in MACAddress macAddress, + in EARP_HardwareTypes hardwareType) : this(interfaceId) + { + Lable = lable; + DefaultIP = zeroconfIp; + DefaultSubnetMask = zeroconfSubnetMask; + staticIP = DefaultIP; + staticSubnetMask = DefaultSubnetMask; + currentIP = StaticIP; + currentSubnetMask = StaticSubnetMask; + MACAddress = macAddress; + HardwareType = hardwareType; + dhcp = false; + zeroConf = true; + currentIP_DHCPStatus = ERDM_DHCPStatusMode.INACTIVE; + } + + public void SetStaticIP(in IPv4Address staticIP, in byte staticSubnetMask) + { + if (staticSubnetMask < 0 || staticSubnetMask > 32) + throw new ArgumentOutOfRangeException(nameof(staticSubnetMask), "Subnet mask must be between 0 and 32"); + StaticIP = staticIP; + StaticSubnetMask = staticSubnetMask; + + this.StaticIPChanged?.InvokeFailSafe(this, EventArgs.Empty); + if (!dhcp) + this.SetCurrentIP(staticIP, staticSubnetMask, false); + } + protected void SetCurrentIP(in IPv4Address currentIP, in byte currentSubnetMask, in bool isGivenByDHCP) + { + if (currentSubnetMask < 0 || currentSubnetMask > 32) + throw new ArgumentOutOfRangeException(nameof(currentSubnetMask), "Subnet mask must be between 0 and 32"); + + this.CurrentIP = currentIP; + this.CurrentSubnetMask = currentSubnetMask; + this.CurrentIP_DHCPStatus = isGivenByDHCP ? ERDM_DHCPStatusMode.ACTIVE : ERDM_DHCPStatusMode.INACTIVE; + + this.CurrentIPChanged?.InvokeFailSafe(this, EventArgs.Empty); + } + + public virtual void RenewDHCP() + { + } + + public virtual void ReleaseDHCP() + { + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine($"Interface: {this.InterfaceId}"); + sb.AppendLine($"Lable: {this.Lable}"); + sb.AppendLine($"CurrentIP: {this.CurrentIP}/{this.CurrentSubnetMask}"); + sb.AppendLine($"MACAddress: {this.MACAddress}"); + sb.AppendLine($"DHCP: {this.DHCP}"); + sb.AppendLine($"ZeroConf: {this.ZeroConf}"); + + return sb.ToString(); + } + + public override bool Equals(object obj) + { + return Equals(obj as Sensor); + } + + public bool Equals(Interface other) + { + return other is not null && + InterfaceId == other.InterfaceId && + Lable == other.Lable && + DefaultIP == other.DefaultIP && + DefaultSubnetMask == other.DefaultSubnetMask && + StaticIP == other.StaticIP && + StaticSubnetMask == other.StaticSubnetMask && + CurrentIP == other.CurrentIP && + CurrentSubnetMask == other.CurrentSubnetMask && + MACAddress == other.MACAddress && + DHCP == other.DHCP && + ZeroConf == other.ZeroConf; + } + + public override int GetHashCode() + { +#if !NETSTANDARD + HashCode hash = new HashCode(); + hash.Add(InterfaceId); + hash.Add(Lable); + hash.Add(DefaultIP); + hash.Add(DefaultSubnetMask); + hash.Add(StaticIP); + hash.Add(StaticSubnetMask); + hash.Add(CurrentIP); + hash.Add(CurrentSubnetMask); + hash.Add(MACAddress); + hash.Add(DHCP); + hash.Add(ZeroConf); + return hash.ToHashCode(); +#else + int hashCode = 1916557166; + hashCode = hashCode * -1521134295 + InterfaceId.GetHashCode(); + hashCode = hashCode * -1521134295 + Lable.GetHashCode(); + hashCode = hashCode * -1521134295 + DefaultIP.GetHashCode(); + hashCode = hashCode * -1521134295 + DefaultSubnetMask.GetHashCode(); + hashCode = hashCode * -1521134295 + StaticIP.GetHashCode(); + hashCode = hashCode * -1521134295 + StaticSubnetMask.GetHashCode(); + hashCode = hashCode * -1521134295 + CurrentIP.GetHashCode(); + hashCode = hashCode * -1521134295 + CurrentSubnetMask.GetHashCode(); + hashCode = hashCode * -1521134295 + MACAddress.GetHashCode(); + hashCode = hashCode * -1521134295 + DHCP.GetHashCode(); + hashCode = hashCode * -1521134295 + ZeroConf.GetHashCode(); + return hashCode; +#endif + } + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/PayloadObject/AcknowledgeTimerHighRes.cs b/RDMSharp/RDM/PayloadObject/AcknowledgeTimerHighRes.cs index cea5934..81c1879 100644 --- a/RDMSharp/RDM/PayloadObject/AcknowledgeTimerHighRes.cs +++ b/RDMSharp/RDM/PayloadObject/AcknowledgeTimerHighRes.cs @@ -1,53 +1,52 @@ using System; using System.Collections.Generic; -namespace RDMSharp +namespace RDMSharp; + +public class AcknowledgeTimerHighRes : AbstractRDMPayloadObject, IAcknowledgeTimer { - public class AcknowledgeTimerHighRes : AbstractRDMPayloadObject, IAcknowledgeTimer + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2208")] + public AcknowledgeTimerHighRes( + TimeSpan estimidatedResponseTime = default) : this((ushort)(estimidatedResponseTime.TotalSeconds * 1000.0)) + { + if (estimidatedResponseTime.TotalSeconds / 10 > ushort.MaxValue) + throw new ArgumentOutOfRangeException("The Timer is to long for the Resolution of 16-bit ushort"); + } + private AcknowledgeTimerHighRes( + ushort _estimidatedResponseTimeRaw = default) + { + this.estimidatedResponseTimeRaw = _estimidatedResponseTimeRaw; + this.EstimidatedResponseTime = TimeSpan.FromSeconds(this.estimidatedResponseTimeRaw / 1000.0); + } + + public TimeSpan EstimidatedResponseTime { get; private set; } + private readonly ushort estimidatedResponseTimeRaw; + public const int PDL = 2; + + public override string ToString() + { + return $"AcknowledgeTimerHighRes: {EstimidatedResponseTime}"; + } + + public static AcknowledgeTimerHighRes FromMessage(RDMMessage msg) + { + RDMMessageInvalidException.ThrowIfInvalidPDL(msg, ERDM_Command.GET_COMMAND_RESPONSE, new ERDM_Parameter[0], PDL); + if (msg.ResponseType != ERDM_ResponseType.ACK_TIMER_HI_RES) throw new Exception($"ResponseType is not {ERDM_ResponseType.ACK_TIMER_HI_RES}"); + + return FromPayloadData(msg.ParameterData); + } + public static AcknowledgeTimerHighRes FromPayloadData(byte[] data) + { + RDMMessageInvalidPDLException.ThrowIfInvalidPDL(data, PDL); + + var i = new AcknowledgeTimerHighRes(Tools.DataToUShort(ref data)); + + return i; + } + public override byte[] ToPayloadData() { - [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2208")] - public AcknowledgeTimerHighRes( - TimeSpan estimidatedResponseTime = default) : this((ushort)(estimidatedResponseTime.TotalSeconds * 1000.0)) - { - if (estimidatedResponseTime.TotalSeconds / 10 > ushort.MaxValue) - throw new ArgumentOutOfRangeException("The Timer is to long for the Resolution of 16-bit ushort"); - } - private AcknowledgeTimerHighRes( - ushort _estimidatedResponseTimeRaw = default) - { - this.estimidatedResponseTimeRaw = _estimidatedResponseTimeRaw; - this.EstimidatedResponseTime = TimeSpan.FromSeconds(this.estimidatedResponseTimeRaw / 1000.0); - } - - public TimeSpan EstimidatedResponseTime { get; private set; } - private readonly ushort estimidatedResponseTimeRaw; - public const int PDL = 2; - - public override string ToString() - { - return $"AcknowledgeTimerHighRes: {EstimidatedResponseTime}"; - } - - public static AcknowledgeTimerHighRes FromMessage(RDMMessage msg) - { - RDMMessageInvalidException.ThrowIfInvalidPDL(msg, ERDM_Command.GET_COMMAND_RESPONSE, new ERDM_Parameter[0], PDL); - if (msg.ResponseType != ERDM_ResponseType.ACK_TIMER_HI_RES) throw new Exception($"ResponseType is not {ERDM_ResponseType.ACK_TIMER_HI_RES}"); - - return FromPayloadData(msg.ParameterData); - } - public static AcknowledgeTimerHighRes FromPayloadData(byte[] data) - { - RDMMessageInvalidPDLException.ThrowIfInvalidPDL(data, PDL); - - var i = new AcknowledgeTimerHighRes(Tools.DataToUShort(ref data)); - - return i; - } - public override byte[] ToPayloadData() - { - List data = new List(); - data.AddRange(Tools.ValueToData(this.estimidatedResponseTimeRaw)); - return data.ToArray(); - } + List data = new List(); + data.AddRange(Tools.ValueToData(this.estimidatedResponseTimeRaw)); + return data.ToArray(); } } \ No newline at end of file diff --git a/RDMSharp/RDM/PayloadObject/GetInterfaceListResponse.cs b/RDMSharp/RDM/PayloadObject/GetInterfaceListResponse.cs index 3dfb5b2..4b06c41 100644 --- a/RDMSharp/RDM/PayloadObject/GetInterfaceListResponse.cs +++ b/RDMSharp/RDM/PayloadObject/GetInterfaceListResponse.cs @@ -7,88 +7,99 @@ namespace RDMSharp { - [DataTreeObject(ERDM_Parameter.LIST_INTERFACES, Command.ECommandDublicate.GetResponse, true, "interfaces")] - public class GetInterfaceListResponse : AbstractRDMPayloadObject - { - [DataTreeObjectConstructor] - public GetInterfaceListResponse([DataTreeObjectParameter("interfaces")] params InterfaceDescriptor[] interfaces) - { - this.Interfaces = interfaces; - } + //public class GetInterfaceListResponse : AbstractRDMPayloadObject + //{ + // [DataTreeObjectConstructor] + // public GetInterfaceListResponse([DataTreeObjectParameter("interfaces")] params InterfaceDescriptor[] interfaces) + // { + // this.Interfaces = interfaces; + // } - [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.INTERFACE_LABEL, Command.ECommandDublicate.GetRequest)] - [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.INTERFACE_HARDWARE_ADDRESS_TYPE, Command.ECommandDublicate.GetRequest)] - [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_DHCP_MODE, Command.ECommandDublicate.GetRequest)] - [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_DHCP_MODE, Command.ECommandDublicate.SetRequest)] - [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_ZEROCONF_MODE, Command.ECommandDublicate.GetRequest)] - [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_ZEROCONF_MODE, Command.ECommandDublicate.SetRequest)] - [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_CURRENT_ADDRESS, Command.ECommandDublicate.GetRequest)] - [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_CURRENT_ADDRESS, Command.ECommandDublicate.SetRequest)] - [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_STATIC_ADDRESS, Command.ECommandDublicate.GetRequest)] - [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_STATIC_ADDRESS, Command.ECommandDublicate.SetRequest)] - [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION, Command.ECommandDublicate.SetRequest)] - [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.INTERFACE_RENEW_DHCP, Command.ECommandDublicate.SetRequest)] - [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.INTERFACE_RELEASE_DHCP, Command.ECommandDublicate.SetRequest)] - [DataTreeObjectProperty("interfaces", 0)] - public InterfaceDescriptor[] Interfaces { get; private set; } - public const int PDL_MIN = 0; - public const int PDL_MAX = 0xE6; + // [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.INTERFACE_LABEL, Command.ECommandDublicate.GetRequest)] + // [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.INTERFACE_HARDWARE_ADDRESS_TYPE, Command.ECommandDublicate.GetRequest)] + // [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_DHCP_MODE, Command.ECommandDublicate.GetRequest)] + // [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_DHCP_MODE, Command.ECommandDublicate.SetRequest)] + // [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_ZEROCONF_MODE, Command.ECommandDublicate.GetRequest)] + // [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_ZEROCONF_MODE, Command.ECommandDublicate.SetRequest)] + // [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_CURRENT_ADDRESS, Command.ECommandDublicate.GetRequest)] + // [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_CURRENT_ADDRESS, Command.ECommandDublicate.SetRequest)] + // [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_STATIC_ADDRESS, Command.ECommandDublicate.GetRequest)] + // [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.IPV4_STATIC_ADDRESS, Command.ECommandDublicate.SetRequest)] + // [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION, Command.ECommandDublicate.SetRequest)] + // [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.INTERFACE_RENEW_DHCP, Command.ECommandDublicate.SetRequest)] + // [DataTreeObjectDependecieProperty("id", nameof(InterfaceDescriptor.InterfaceId), ERDM_Parameter.INTERFACE_RELEASE_DHCP, Command.ECommandDublicate.SetRequest)] + // [DataTreeObjectProperty("interfaces", 0)] + // public InterfaceDescriptor[] Interfaces { get; private set; } + // public const int PDL_MIN = 0; + // public const int PDL_MAX = 0xE6; - public override string ToString() - { - StringBuilder b = new StringBuilder(); - b.AppendLine("GetInterfaceListResponse"); - b.AppendLine($"Interfaces:"); - if (Interfaces is not null) - foreach (InterfaceDescriptor _interface in Interfaces) - b.AppendLine(_interface.ToString()); + // public override string ToString() + // { + // StringBuilder b = new StringBuilder(); + // b.AppendLine("GetInterfaceListResponse"); + // b.AppendLine($"Interfaces:"); + // if (Interfaces is not null) + // foreach (InterfaceDescriptor _interface in Interfaces) + // b.AppendLine(_interface.ToString()); - return b.ToString(); - } - public static GetInterfaceListResponse FromMessage(RDMMessage msg) - { - RDMMessageInvalidException.ThrowIfInvalidPDLRange(msg, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.LIST_INTERFACES, PDL_MIN, PDL_MAX); + // return b.ToString(); + // } + // public static GetInterfaceListResponse FromMessage(RDMMessage msg) + // { + // RDMMessageInvalidException.ThrowIfInvalidPDLRange(msg, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.LIST_INTERFACES, PDL_MIN, PDL_MAX); - return FromPayloadData(msg.ParameterData); - } - public static GetInterfaceListResponse FromPayloadData(byte[] data) - { - RDMMessageInvalidPDLException.ThrowIfInvalidPDLRange(data, PDL_MIN, PDL_MAX); + // return FromPayloadData(msg.ParameterData); + // } + // public static GetInterfaceListResponse FromPayloadData(byte[] data) + // { + // RDMMessageInvalidPDLException.ThrowIfInvalidPDLRange(data, PDL_MIN, PDL_MAX); - List _interfaces = new List(); - int pdl = 6; - while (data.Length >= pdl) - { - var bytes = data.Take(pdl).ToArray(); - _interfaces.Add(InterfaceDescriptor.FromPayloadData(bytes)); - data = data.Skip(pdl).ToArray(); - } + // List _interfaces = new List(); + // int pdl = 6; + // while (data.Length >= pdl) + // { + // var bytes = data.Take(pdl).ToArray(); + // _interfaces.Add(InterfaceDescriptor.FromPayloadData(bytes)); + // data = data.Skip(pdl).ToArray(); + // } - var i = new GetInterfaceListResponse(_interfaces.ToArray()); + // var i = new GetInterfaceListResponse(_interfaces.ToArray()); - if (data.Length != 0) - throw new Exception("After deserialization data should be empty!"); + // if (data.Length != 0) + // throw new Exception("After deserialization data should be empty!"); - return i; - } - public override byte[] ToPayloadData() - { - List data = new List(); - foreach (InterfaceDescriptor _interface in Interfaces) - data.AddRange(_interface.ToPayloadData()); - return data.ToArray(); - } - } + // return i; + // } + // public override byte[] ToPayloadData() + // { + // List data = new List(); + // foreach (InterfaceDescriptor _interface in Interfaces) + // data.AddRange(_interface.ToPayloadData()); + // return data.ToArray(); + // } + //} + [DataTreeObject(ERDM_Parameter.LIST_INTERFACES, Command.ECommandDublicate.GetResponse, true, "interfaces")] public class InterfaceDescriptor : AbstractRDMPayloadObject { - public InterfaceDescriptor(uint interfaceId = 0, ushort hardwareType = 0) + [DataTreeObjectConstructor] + public InterfaceDescriptor( + [DataTreeObjectParameter("id")] uint interfaceId = 0, + [DataTreeObjectParameter("hardware_type")] ushort hardwareType = 0) + { + this.InterfaceId = interfaceId; + this._HardwareType = hardwareType; + } + public InterfaceDescriptor(uint interfaceId, EARP_HardwareTypes hardwareType) { this.InterfaceId = interfaceId; - this.HardwareType = hardwareType; + this._HardwareType = (ushort)hardwareType; } + [DataTreeObjectProperty("id", 0)] public uint InterfaceId { get; private set; } - public ushort HardwareType { get; private set; } + [DataTreeObjectProperty("hardware_type", 1)] + public ushort _HardwareType { get; private set; } + public EARP_HardwareTypes HardwareType { get => (EARP_HardwareTypes)this._HardwareType; } public const int PDL = 6; public override string ToString() diff --git a/RDMSharp/RDM/PayloadObject/GetSetIPV4_xxx_Mode.cs b/RDMSharp/RDM/PayloadObject/GetSetIPV4_xxx_Mode.cs index 2033628..5cf1633 100644 --- a/RDMSharp/RDM/PayloadObject/GetSetIPV4_xxx_Mode.cs +++ b/RDMSharp/RDM/PayloadObject/GetSetIPV4_xxx_Mode.cs @@ -27,7 +27,7 @@ public GetSetIPV4_xxx_Mode( public override string ToString() { - return $"GetSetDHCPMode: {InterfaceId} - {Enabled}"; + return $"GetSet-xxx-Mode: {InterfaceId} - {Enabled}"; } public static GetSetIPV4_xxx_Mode FromMessage(RDMMessage msg) diff --git a/RDMSharp/RDM/PayloadObject/RDMProxiedDevices.cs b/RDMSharp/RDM/PayloadObject/RDMProxiedDevices.cs index b045702..944a84a 100644 --- a/RDMSharp/RDM/PayloadObject/RDMProxiedDevices.cs +++ b/RDMSharp/RDM/PayloadObject/RDMProxiedDevices.cs @@ -1,59 +1,61 @@ using RDMSharp.Metadata; +using RDMSharp.Metadata.JSON; using System; using System.Collections.Generic; using System.Text; -namespace RDMSharp +namespace RDMSharp; + +[DataTreeObject(ERDM_Parameter.PROXIED_DEVICES, Command.ECommandDublicate.GetResponse, true, "device_uids")] +public class RDMProxiedDevices : AbstractRDMPayloadObject { - //[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 + [DataTreeObjectConstructor] + public RDMProxiedDevices([DataTreeObjectParameter(ERDM_Parameter.PROXIED_DEVICES, "device_uids", true)] params UID[] devices) + { + this.Devices = devices; + } + + [DataTreeObjectProperty("device_uids", 0)] + public UID[] Devices { get; private set; } + public const int PDL_MIN = 0; + public const int PDL_MAX = 0xE4; + + public override string ToString() { - [DataTreeObjectConstructor] - public RDMProxiedDevices(/*[DataTreeObjectParameter("device_uid", true)]*/ params UID[] devices) - { - this.Devices = devices; - } - - public UID[] Devices { get; private set; } - public const int PDL_MIN = 0; - public const int PDL_MAX = 0xE4; - - public override string ToString() - { - StringBuilder b = new StringBuilder(); - b.AppendLine("RDMProxiedDevices"); - b.AppendLine($"Devices:"); + StringBuilder b = new StringBuilder(); + b.AppendLine("RDMProxiedDevices"); + b.AppendLine($"Devices:"); + if (Devices is not null) foreach (UID device in Devices) b.AppendLine(device.ToString()); - return b.ToString(); - } - public static RDMProxiedDevices FromMessage(RDMMessage msg) - { - RDMMessageInvalidException.ThrowIfInvalidPDLRange(msg, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.PROXIED_DEVICES, PDL_MIN, PDL_MAX); - - return FromPayloadData(msg.ParameterData); - } - public static RDMProxiedDevices FromPayloadData(byte[] data) - { - RDMMessageInvalidPDLException.ThrowIfInvalidPDLRange(data, PDL_MIN, PDL_MAX); - - List uids = new List(); - while (data.Length >= 6) - uids.Add(Tools.DataToRDMUID(ref data)); - - var i = new RDMProxiedDevices(uids.ToArray()); - - if (data.Length != 0) - throw new Exception("After deserialization data should be empty!"); - - return i; - } - public override byte[] ToPayloadData() - { - List data = new List(); - data.AddRange(Tools.ValueToData(this.Devices)); - return data.ToArray(); - } + return b.ToString(); + } + public static RDMProxiedDevices FromMessage(RDMMessage msg) + { + RDMMessageInvalidException.ThrowIfInvalidPDLRange(msg, ERDM_Command.GET_COMMAND_RESPONSE, ERDM_Parameter.PROXIED_DEVICES, PDL_MIN, PDL_MAX); + + return FromPayloadData(msg.ParameterData); + } + public static RDMProxiedDevices FromPayloadData(byte[] data) + { + RDMMessageInvalidPDLException.ThrowIfInvalidPDLRange(data, PDL_MIN, PDL_MAX); + + List uids = new List(); + while (data.Length >= 6) + uids.Add(Tools.DataToRDMUID(ref data)); + + var i = new RDMProxiedDevices(uids.ToArray()); + + if (data.Length != 0) + throw new Exception("After deserialization data should be empty!"); + + return i; + } + public override byte[] ToPayloadData() + { + List data = new List(); + data.AddRange(Tools.ValueToData(this.Devices)); + return data.ToArray(); } } \ No newline at end of file diff --git a/RDMSharp/RDM/PeerToPeerProcess.cs b/RDMSharp/RDM/PeerToPeerProcess.cs index 8e14d40..1807f0a 100644 --- a/RDMSharp/RDM/PeerToPeerProcess.cs +++ b/RDMSharp/RDM/PeerToPeerProcess.cs @@ -3,194 +3,301 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Threading; using System.Threading.Tasks; using static RDMSharp.Metadata.JSON.Command; -namespace RDMSharp +namespace RDMSharp; + +public class PeerToPeerProcess : INotifyPropertyChanged { - public class PeerToPeerProcess - { - private static readonly ILogger Logger = Logging.CreateLogger(); + private static readonly ILogger Logger = Logging.CreateLogger(); - public enum EPeerToPeerProcessState + public enum EPeerToPeerProcessState + { + Waiting, + Running, + Finished, + Failed + } + public readonly ERDM_Command Command; + public readonly UID UID; + public readonly SubDevice SubDevice; + public ParameterBag ParameterBag { get; private set; } + public readonly DataTreeBranch RequestPayloadObject; + private DataTreeBranch _responsePayloadObject = DataTreeBranch.Unset; + public DataTreeBranch ResponsePayloadObject + { + get { - Waiting, - Running, - Finished, - Failed + return _responsePayloadObject; } - public readonly ERDM_Command Command; - public readonly UID UID; - public readonly SubDevice SubDevice; - public ParameterBag ParameterBag { get; private set; } - 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; } - public ERDM_NackReason[] NackReason { get; private set; } - - private RDMMessage request = null; - private RDMMessage response = null; - public Func BeforeSendMessage; - public Func ResponseMessage; - public byte MessageCounter => response?.MessageCounter ?? 0; - private SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1); - - public PeerToPeerProcess(ERDM_Command command, UID uid, SubDevice subDevice, ParameterBag parameterBag, DataTreeBranch? payloadObject = null) + private set { - 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}"); + if (_responsePayloadObject == value) + return; + _responsePayloadObject = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ResponsePayloadObject))); + } + } - Command = command; - UID = uid; - SubDevice = subDevice; - ParameterBag = parameterBag; - RequestPayloadObject = payloadObject ?? DataTreeBranch.Unset; + public MetadataJSONObjectDefine Define { get; private set; } + private EPeerToPeerProcessState _state = EPeerToPeerProcessState.Waiting; + public EPeerToPeerProcessState State + { + get + { + return _state; + } + private set + { + if (_state == value) + return; + _state = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(State))); + } + } - Logger?.LogTrace($"Create PeerToPeerProcess: {Command} UID: {UID} SubDevice: {SubDevice} Parameter: {ParameterBag.PID} PayloadObject: {RequestPayloadObject.ToString()}"); + private Exception _exception; + public Exception Exception + { + get + { + return _exception; - //if (ParameterBag.PID != ERDM_Parameter.QUEUED_MESSAGE) - Define = MetadataFactory.GetDefine(ParameterBag); } - - public async Task Run(AsyncRDMRequestHelper asyncRDMRequestHelper = null) + private set { - asyncRDMRequestHelper ??= RDMSharp.Instance.AsyncRDMRequestHelper; - if (State != EPeerToPeerProcessState.Waiting) + if (_exception == value) return; - if (SemaphoreSlim.CurrentCount == 0) + _exception = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Exception))); + } + } + + private ERDM_NackReason? _nackReason; + public ERDM_NackReason? NackReason + { + get + { + return _nackReason; + } + private set + { + if (_nackReason == value) return; - await SemaphoreSlim.WaitAsync(); - State = EPeerToPeerProcessState.Running; - try + _nackReason = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(NackReason))); + } + } + + private RDMMessage request = null; + private RDMMessage response = null; + public Func BeforeSendMessage; + public Func ResponseMessage; + + private ConcurrentBag requestResponseHistory = new ConcurrentBag(); + public IEnumerable RequestResponseHistory => requestResponseHistory.ToList(); + + internal event EventHandler OnRequestResponseHistoryAdded; + + public byte MessageCounter => response?.MessageCounter ?? 0; + private SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1); + + public event PropertyChangedEventHandler PropertyChanged; + + 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; + + Logger?.LogTrace($"Create PeerToPeerProcess: {Command} UID: {UID} SubDevice: {SubDevice} Parameter: {ParameterBag.PID} PayloadObject: {RequestPayloadObject.ToString()}"); + + //if (ParameterBag.PID != ERDM_Parameter.QUEUED_MESSAGE) + Define = MetadataFactory.GetDefine(ParameterBag); + } + + public async Task Run(AsyncRDMRequestHelper asyncRDMRequestHelper = null) + { + asyncRDMRequestHelper ??= RDMSharp.Instance.AsyncRDMRequestHelper; + if (State != EPeerToPeerProcessState.Waiting) + return; + if (SemaphoreSlim.CurrentCount == 0) + return; + await SemaphoreSlim.WaitAsync(); + State = EPeerToPeerProcessState.Running; + try + { + ECommandDublicate commandRequest = ECommandDublicate.GetRequest; + if (Command == ERDM_Command.SET_COMMAND) + commandRequest = ECommandDublicate.SetRequest; + + ECommandDublicate commandResponse = ECommandDublicate.GetResponse; + if (Command == ERDM_Command.SET_COMMAND) + commandResponse = ECommandDublicate.SetResponse; + + byte[] parameterData = null; + if (Define != null) + parameterData = MetadataFactory.ParsePayloadToData(Define, commandRequest, RequestPayloadObject).First(); + request = new RDMMessage() + { + Command = Command, + DestUID = UID, + SubDevice = SubDevice, + Parameter = ParameterBag.PID, + ParameterData = parameterData + }; + List bytes = new List(); + bool done = false; + int counter = 0; + do { - ECommandDublicate commandRequest = ECommandDublicate.GetRequest; - if (Command == ERDM_Command.SET_COMMAND) - commandRequest = ECommandDublicate.SetRequest; - - ECommandDublicate commandResponse = ECommandDublicate.GetResponse; - if (Command == ERDM_Command.SET_COMMAND) - commandResponse = ECommandDublicate.SetResponse; - - byte[] parameterData = null; - if (Define != null) - parameterData = MetadataFactory.ParsePayloadToData(Define, commandRequest, RequestPayloadObject).First(); - request = new RDMMessage() + await RDMSharp.Instance.lockTransaktion(UID).WaitAsync(TimeSpan.FromSeconds(7)); + counter++; + if (response?.ResponseType == ERDM_ResponseType.ACK) + return; + if (BeforeSendMessage != null) + await BeforeSendMessage(request); + var historyEntry = new RequestResponseHistoryEntry(request); + requestResponseHistory.Add(historyEntry); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(RequestResponseHistory))); + OnRequestResponseHistoryAdded?.Invoke(this, historyEntry); + + RequestResult responseResult; + try { - Command = Command, - DestUID = UID, - SubDevice = SubDevice, - Parameter = ParameterBag.PID, - ParameterData = parameterData - }; - List bytes = new List(); - bool done = false; - int counter = 0; - do + responseResult = await asyncRDMRequestHelper.RequestMessage(request); + } + finally { - counter++; - if (BeforeSendMessage != null) - await BeforeSendMessage(request); - if (response?.ResponseType == ERDM_ResponseType.ACK) - return; - var responseResult = await asyncRDMRequestHelper.RequestMessage(request); - if (!responseResult.Success || - (responseResult.Response is not null && responseResult.Response.ResponseType == ERDM_ResponseType.NACK_REASON)) - { - State = EPeerToPeerProcessState.Failed; - NackReason= responseResult.Response.NackReason; - if (responseResult.Response is not null) - ResponseMessage?.InvokeFailSafe(responseResult.Response); - return; - } - response = responseResult.Response; - switch (responseResult.Response.ResponseType) - { - case ERDM_ResponseType.ACK_TIMER: - case ERDM_ResponseType.ACK_TIMER_HI_RES: - if (response.Value is IAcknowledgeTimer timer) - { - await Task.Delay(timer.EstimidatedResponseTime); - request.Parameter = ERDM_Parameter.QUEUED_MESSAGE; - //Send Message on next loop - continue; - } - break; - case ERDM_ResponseType.ACK: - bytes.AddRange(response.ParameterData); - done = true; - var _byteArray = bytes.ToArray(); - bytes.Clear(); - bytes = null; - if (request.Parameter == ERDM_Parameter.QUEUED_MESSAGE) + RDMSharp.Instance.unlockTransaktion(UID); + } + + if (responseResult.Timeout) + { + historyEntry.SetResponse(responseResult.Response, "Timeout"); + State = EPeerToPeerProcessState.Failed; + return; + } + if (responseResult.Disposing) + { + historyEntry.SetResponse(responseResult.Response, "Disposing"); + State = EPeerToPeerProcessState.Failed; + return; + } + if (!responseResult.Success || + (responseResult.Response is not null && responseResult.Response.ResponseType == ERDM_ResponseType.NACK_REASON)) + { + historyEntry.SetResponse(responseResult.Response, "NACK"); + State = EPeerToPeerProcessState.Failed; + NackReason = responseResult.Response?.NackReason; + if (responseResult.Response is not null) + ResponseMessage?.InvokeFailSafe(responseResult.Response); + return; + } + + response = responseResult.Response; + historyEntry.SetResponse(response); + switch (responseResult.Response.ResponseType) + { + case ERDM_ResponseType.ACK_TIMER: + case ERDM_ResponseType.ACK_TIMER_HI_RES: + if (response.AcknowledgeTimer is IAcknowledgeTimer timer) + { + await Task.Delay(timer.EstimidatedResponseTime); + request = new RDMMessage() { - ParameterBag = new ParameterBag(response.Parameter, ParameterBag.ManufacturerID, ParameterBag.DeviceModelID, ParameterBag.SoftwareVersionID); - Define = MetadataFactory.GetDefine(ParameterBag); - } - if (Define != null) - ResponsePayloadObject = MetadataFactory.ParseDataToPayload(Define, commandResponse, _byteArray); - State = EPeerToPeerProcessState.Finished; - - ResponseMessage?.InvokeFailSafe(responseResult.Response); - return; - case ERDM_ResponseType.ACK_OVERFLOW: - bytes.AddRange(response.ParameterData); + Command = ERDM_Command.GET_COMMAND, + DestUID = UID, + SubDevice = SubDevice, + Parameter = ERDM_Parameter.QUEUED_MESSAGE, + ParameterData = new byte[] { 2 } + }; + //Send Message on next loop continue; + } + break; + case ERDM_ResponseType.ACK: + bytes.AddRange(response.ParameterData); + done = true; + var _byteArray = bytes.ToArray(); + bytes.Clear(); + bytes = null; + if (request.Parameter == ERDM_Parameter.QUEUED_MESSAGE) + { + ParameterBag = new ParameterBag(response.Parameter, ParameterBag.ManufacturerID, ParameterBag.DeviceModelID, ParameterBag.SoftwareVersionID); + Define = MetadataFactory.GetDefine(ParameterBag); + } + if (Define != null) + ResponsePayloadObject = MetadataFactory.ParseDataToPayload(Define, commandResponse, _byteArray); + State = EPeerToPeerProcessState.Finished; + + ResponseMessage?.InvokeFailSafe(responseResult.Response); + return; + case ERDM_ResponseType.ACK_OVERFLOW: + bytes.AddRange(response.ParameterData); + continue; - } - //if ((response.ResponseType == ERDM_ResponseType.ACK_TIMER || - // response.ResponseType == ERDM_ResponseType.ACK_TIMER_HI_RES) && response.Value is IAcknowledgeTimer timer) - //{ - // await Task.Delay(timer.EstimidatedResponseTime); - // request.Parameter = ERDM_Parameter.QUEUED_MESSAGE; - // //Send Message on next loop - // continue; - //} - //if (response.ResponseType == ERDM_ResponseType.ACK) - //{ - // bytes.AddRange(response.ParameterData); - // done = true; - // var _byteArray = bytes.ToArray(); - // bytes.Clear(); - // bytes = null; - // if (request.Parameter == ERDM_Parameter.QUEUED_MESSAGE) - // { - // ParameterBag = new ParameterBag(response.Parameter, ParameterBag.ManufacturerID, ParameterBag.DeviceModelID, ParameterBag.SoftwareVersionID); - // Define = MetadataFactory.GetDefine(ParameterBag); - // } - // if (Define != null) - // ResponsePayloadObject = MetadataFactory.ParseDataToPayload(Define, commandResponse, _byteArray); - // State = EPeerToPeerProcessState.Finished; - - // ResponseMessage?.InvokeFailSafe(responseResult.Response); - // return; - //} - //if (response.ResponseType == ERDM_ResponseType.ACK_OVERFLOW) - //{ - // bytes.AddRange(response.ParameterData); - // //Do nothing else send another Request - // //Send Message on next loop - // continue; - //} } - while (!done && State == EPeerToPeerProcessState.Running); - } - catch (Exception e) - { - Logger?.LogError(e); - this.Exception = e; - State = EPeerToPeerProcessState.Failed; - } - finally - { - SemaphoreSlim.Release(); + //if ((response.ResponseType == ERDM_ResponseType.ACK_TIMER || + // response.ResponseType == ERDM_ResponseType.ACK_TIMER_HI_RES) && response.Value is IAcknowledgeTimer timer) + //{ + // await Task.Delay(timer.EstimidatedResponseTime); + // request.Parameter = ERDM_Parameter.QUEUED_MESSAGE; + // //Send Message on next loop + // continue; + //} + //if (response.ResponseType == ERDM_ResponseType.ACK) + //{ + // bytes.AddRange(response.ParameterData); + // done = true; + // var _byteArray = bytes.ToArray(); + // bytes.Clear(); + // bytes = null; + // if (request.Parameter == ERDM_Parameter.QUEUED_MESSAGE) + // { + // ParameterBag = new ParameterBag(response.Parameter, ParameterBag.ManufacturerID, ParameterBag.DeviceModelID, ParameterBag.SoftwareVersionID); + // Define = MetadataFactory.GetDefine(ParameterBag); + // } + // if (Define != null) + // ResponsePayloadObject = MetadataFactory.ParseDataToPayload(Define, commandResponse, _byteArray); + // State = EPeerToPeerProcessState.Finished; + + // ResponseMessage?.InvokeFailSafe(responseResult.Response); + // return; + //} + //if (response.ResponseType == ERDM_ResponseType.ACK_OVERFLOW) + //{ + // bytes.AddRange(response.ParameterData); + // //Do nothing else send another Request + // //Send Message on next loop + // continue; + //} } + while (!done && State == EPeerToPeerProcessState.Running); + } + catch (Exception e) + { + Logger?.LogError(e); + this.Exception = e; + State = EPeerToPeerProcessState.Failed; + } + finally + { + var last = requestResponseHistory.LastOrDefault(); + if (last is not null) + if (last.State is null) + last.SetResponse(null, "Fail"); + SemaphoreSlim.Release(); } } -} \ No newline at end of file +} diff --git a/RDMSharp/RDM/RDMMessage.cs b/RDMSharp/RDM/RDMMessage.cs index 1429a2a..c0de783 100644 --- a/RDMSharp/RDM/RDMMessage.cs +++ b/RDMSharp/RDM/RDMMessage.cs @@ -1,558 +1,625 @@ using Microsoft.Extensions.Logging; using RDMSharp.Metadata; -using RDMSharp.Metadata.JSON; using System; using System.Collections.Generic; using System.Linq; using System.Text; +using _AcknowledgeTimer = RDMSharp.AcknowledgeTimer; -namespace RDMSharp -{ - public class RDMMessage : IEquatable - { - private static readonly ILogger Logger = Logging.CreateLogger(); - private byte[] _parameterData = Array.Empty(); - private byte? preambleCount = null; +namespace RDMSharp; - public RDMMessage() - { +public class RDMMessage : IEquatable +{ + private static readonly ILogger Logger = Logging.CreateLogger(); + private byte[] _parameterData = Array.Empty(); + private byte? preambleCount = null; - } - public RDMMessage(in byte[] data) - { + public RDMMessage() + { + + } + public RDMMessage(in byte[] data) + { #if NETSTANDARD - if (data == null) - throw new ArgumentNullException(nameof(data)); + if (data == null) + throw new ArgumentNullException(nameof(data)); #else - ArgumentNullException.ThrowIfNull(data); + ArgumentNullException.ThrowIfNull(data); #endif - if (data.Length < 26) + if (data.Length < 26) + { + if (data.Length >= 17 && (data[0] == 0xFE || data[0] == 0xAA)) { - if (data.Length >= 17 && (data[0] == 0xFE || data[0] == 0xAA)) - { - Command = ERDM_Command.DISCOVERY_COMMAND_RESPONSE; - Parameter = ERDM_Parameter.DISC_UNIQUE_BRANCH; + Command = ERDM_Command.DISCOVERY_COMMAND_RESPONSE; + Parameter = ERDM_Parameter.DISC_UNIQUE_BRANCH; - //Parse Byte[] According to Spec - //data could have a Preample of 0 - 7 bytes, search for Preample seperator - int dataIndex = Array.IndexOf(data, (byte)0xAA); - if (dataIndex == -1) //No Preamble seperator found, corrupt - throw new Exception("No Preamble seperator found, corrupt"); - if (data.Length - dataIndex < 17) //Data Missing, corrupt - throw new Exception("Data Missing, corrupt"); - if (dataIndex >= 8) //Data Missing, corrupt - throw new Exception("Data Missing, corrupt"); + //Parse Byte[] According to Spec + //data could have a Preample of 0 - 7 bytes, search for Preample seperator + int dataIndex = Array.IndexOf(data, (byte)0xAA); + if (dataIndex == -1) //No Preamble seperator found, corrupt + throw new Exception("No Preamble seperator found, corrupt"); + if (data.Length - dataIndex < 17) //Data Missing, corrupt + throw new Exception("Data Missing, corrupt"); + if (dataIndex >= 8) //Data Missing, corrupt + throw new Exception("Data Missing, corrupt"); - preambleCount = (byte)dataIndex; + preambleCount = (byte)dataIndex; - //Calc Checksum - DeserializedChecksum1 = (ushort)(((data[dataIndex + 13] & data[dataIndex + 14]) << 8) | - (data[dataIndex + 15] & data[dataIndex + 16])); + //Calc Checksum + DeserializedChecksum1 = (ushort)(((data[dataIndex + 13] & data[dataIndex + 14]) << 8) | + (data[dataIndex + 15] & data[dataIndex + 16])); - DeserializedChecksum2 = (ushort)data.Skip(dataIndex + 1).Take(12).Sum(c => (int)c); + DeserializedChecksum2 = (ushort)data.Skip(dataIndex + 1).Take(12).Sum(c => (int)c); - ushort manId = (ushort)(((data[dataIndex + 1] & data[dataIndex + 2]) << 8) | - (data[dataIndex + 3] & data[dataIndex + 4])); + ushort manId = (ushort)(((data[dataIndex + 1] & data[dataIndex + 2]) << 8) | + (data[dataIndex + 3] & data[dataIndex + 4])); - uint devId = (uint)(((data[dataIndex + 5] & data[dataIndex + 6]) << 24) | - ((data[dataIndex + 7] & data[dataIndex + 8]) << 16) | - ((data[dataIndex + 9] & data[dataIndex + 10]) << 8) | - (data[dataIndex + 11] & data[dataIndex + 12])); - - SourceUID = new UID(manId, devId); - return; - } - else - throw new IndexOutOfRangeException($"{nameof(data)} Length is {data.Length} but has to be at least 26"); - } - - //Check startcode and sub-startcode - if (data[0] != 0xCC || data[1] != 0x01) - throw new Exception("Start-Code invalid"); - - byte length = data[2]; - - if (data.Length < length + 2) - throw new Exception("DataLength not fit Length in Header"); - - //Calc Checksum - DeserializedChecksum1 = (ushort)((data[length] << 8) | data[length + 1]); - DeserializedChecksum2 = (ushort)data.Take(length).Sum(c => (int)c); - - ushort manIdDest = (ushort)((data[3] << 8) | data[4]); - uint devIdDest = (uint)((data[5] << 24) | (data[6] << 16) | (data[7] << 8) | data[8]); - ushort manIdSource = (ushort)((data[9] << 8) | data[10]); - uint devIdSource = (uint)((data[11] << 24) | (data[12] << 16) | (data[13] << 8) | data[14]); - - byte paramLength = data[23]; - - SourceUID = new UID(manIdSource, devIdSource); - DestUID = new UID(manIdDest, devIdDest); - TransactionCounter = data[15]; - PortID_or_Responsetype = data[16]; - MessageCounter = data[17]; - SubDevice = new SubDevice((ushort)((data[18] << 8) | data[19])); - Command = (ERDM_Command)data[20]; - Parameter = (ERDM_Parameter)((data[21] << 8) | data[22]); - ParameterData = data.Skip(24).Take(paramLength).ToArray(); - } - public RDMMessage(params ERDM_NackReason[] nackReasons) - { - if (nackReasons == null) - return; - if (nackReasons.Length == 0) - return; + uint devId = (uint)(((data[dataIndex + 5] & data[dataIndex + 6]) << 24) | + ((data[dataIndex + 7] & data[dataIndex + 8]) << 16) | + ((data[dataIndex + 9] & data[dataIndex + 10]) << 8) | + (data[dataIndex + 11] & data[dataIndex + 12])); - nackReason = nackReasons; - PortID_or_Responsetype = (byte)ERDM_ResponseType.NACK_REASON; + SourceUID = new UID(manId, devId); + return; + } + else + throw new IndexOutOfRangeException($"{nameof(data)} Length is {data.Length} but has to be at least 26"); } - public byte MessageLength + //Check startcode and sub-startcode + if (data[0] != 0xCC || data[1] != 0x01) + throw new Exception("Start-Code invalid"); + + byte length = data[2]; + + if (data.Length < length + 2) + throw new Exception("DataLength not fit Length in Header"); + + //Calc Checksum + DeserializedChecksum1 = (ushort)((data[length] << 8) | data[length + 1]); + DeserializedChecksum2 = (ushort)data.Take(length).Sum(c => (int)c); + + ushort manIdDest = (ushort)((data[3] << 8) | data[4]); + uint devIdDest = (uint)((data[5] << 24) | (data[6] << 16) | (data[7] << 8) | data[8]); + ushort manIdSource = (ushort)((data[9] << 8) | data[10]); + uint devIdSource = (uint)((data[11] << 24) | (data[12] << 16) | (data[13] << 8) | data[14]); + + byte paramLength = data[23]; + + SourceUID = new UID(manIdSource, devIdSource); + DestUID = new UID(manIdDest, devIdDest); + TransactionCounter = data[15]; + PortID_or_Responsetype = data[16]; + ControllerFlags_or_MessageCounter = data[17]; + SubDevice = new SubDevice((ushort)((data[18] << 8) | data[19])); + Command = (ERDM_Command)data[20]; + Parameter = (ERDM_Parameter)((data[21] << 8) | data[22]); + ParameterData = data.Skip(24).Take(paramLength).ToArray(); + } + public RDMMessage(ERDM_NackReason nackReason) + { + _nackReason = nackReason; + PortID_or_Responsetype = (byte)ERDM_ResponseType.NACK_REASON; + } + public RDMMessage(AcknowledgeTimer acknowledgeTimer) + { + _acknowledgeTimer = acknowledgeTimer; + PortID_or_Responsetype = (byte)ERDM_ResponseType.ACK_TIMER; + } + public RDMMessage(AcknowledgeTimerHighRes acknowledgeTimerHighRes) + { + _acknowledgeTimer = acknowledgeTimerHighRes; + PortID_or_Responsetype = (byte)ERDM_ResponseType.ACK_TIMER_HI_RES; + } + + public byte MessageLength + { + get { - get - { - byte b = 24; //The 1st 24 bytes are always the same - b += PDL; - return b; - } + byte b = 24; //The 1st 24 bytes are always the same + b += PDL; + return b; } + } - public UID SourceUID { get; set; } + public UID SourceUID { get; set; } - public UID DestUID { get; set; } + public UID DestUID { get; set; } - public byte TransactionCounter { get; set; } + public byte TransactionCounter { get; set; } - private byte portID_or_Responsetype; - public byte PortID_or_Responsetype + private byte portID_or_Responsetype; + public byte PortID_or_Responsetype + { + get + { + return portID_or_Responsetype; + } + set { - get - { - return portID_or_Responsetype; - } - set - { - if (value == portID_or_Responsetype) - return; + if (value == portID_or_Responsetype) + return; - valueCache = null; + valueCache = null; - portID_or_Responsetype = value; - } - } - - public byte MessageCounter { get; set; } - public byte? PreambleCount + portID_or_Responsetype = value; + } + } + + public byte? MessageCounter + { + get + { + if (this.Command.HasFlag(ERDM_Command.RESPONSE)) + return ControllerFlags_or_MessageCounter; + return null; + } + } + public ERDM_ControllerFlags? ControllerFlags + { + get + { + if (!this.Command.HasFlag(ERDM_Command.RESPONSE)) + return (ERDM_ControllerFlags)ControllerFlags_or_MessageCounter; + return null; + } + } + public byte ControllerFlags_or_MessageCounter { get; set; } + public byte? PreambleCount + { + get { - get - { - if (this.Command != ERDM_Command.DISCOVERY_COMMAND_RESPONSE) - return null; + if (this.Command != ERDM_Command.DISCOVERY_COMMAND_RESPONSE) + return null; - if (this.Parameter != ERDM_Parameter.DISC_UNIQUE_BRANCH) - return null; + if (this.Parameter != ERDM_Parameter.DISC_UNIQUE_BRANCH) + return null; - return preambleCount; - } - set - { - if (this.Command != ERDM_Command.DISCOVERY_COMMAND_RESPONSE) - return; + return preambleCount; + } + set + { + if (this.Command != ERDM_Command.DISCOVERY_COMMAND_RESPONSE) + return; - if (this.Parameter != ERDM_Parameter.DISC_UNIQUE_BRANCH) - return; + if (this.Parameter != ERDM_Parameter.DISC_UNIQUE_BRANCH) + return; - if (preambleCount == value) - return; + if (preambleCount == value) + return; - preambleCount = value; - } - } + preambleCount = value; + } + } - public SubDevice SubDevice { get; set; } + public SubDevice SubDevice { get; set; } - private ERDM_Command command; - public ERDM_Command Command + private ERDM_Command command; + public ERDM_Command Command + { + get { - get - { - return command; - } - set - { - if (value == command) - return; - valueCache = null; - command = value; - } + return command; } + set + { + if (value == command) + return; + valueCache = null; + command = value; + } + } - private ERDM_Parameter parameter; - public ERDM_Parameter Parameter + private ERDM_Parameter parameter; + public ERDM_Parameter Parameter + { + get { - get - { - return parameter; - } - set - { - if (value == parameter) - return; - valueCache = null; - parameter = value; - } + return parameter; + } + set + { + if (value == parameter) + return; + valueCache = null; + parameter = value; } + } - private ERDM_NackReason[] nackReason = null; + private ERDM_NackReason? _nackReason = null; - public ERDM_NackReason[] NackReason + public ERDM_NackReason? NackReason + { + get { - get - { - if (ResponseType != ERDM_ResponseType.NACK_REASON) - return null; + if (ResponseType != ERDM_ResponseType.NACK_REASON) + return null; - if (nackReason != null) - return nackReason; + if (_nackReason != null) + return _nackReason; + byte[] data = _parameterData.ToArray(); - List reasons = new List(); - while (_parameterData.Length > 1) - { - var res = Tools.DataToEnum(ref _parameterData); - reasons.Add(res); - } - nackReason = reasons.ToArray(); - return nackReason; - } + _nackReason = Tools.DataToEnum(ref data); + return _nackReason; } + } + private IAcknowledgeTimer? _acknowledgeTimer = null; - public byte PDL + public IAcknowledgeTimer? AcknowledgeTimer + { + get { - get { return (byte)ParameterData.Length; } + if (ResponseType != ERDM_ResponseType.ACK_TIMER && ResponseType != ERDM_ResponseType.ACK_TIMER_HI_RES) + return null; + + if (_acknowledgeTimer != null) + return _acknowledgeTimer; + + byte[] data = _parameterData.ToArray(); + + switch (ResponseType) + { + case ERDM_ResponseType.ACK_TIMER: + _acknowledgeTimer = _AcknowledgeTimer.FromPayloadData(data); + break; + case ERDM_ResponseType.ACK_TIMER_HI_RES: + _acknowledgeTimer = AcknowledgeTimerHighRes.FromPayloadData(data); + break; + } + return _acknowledgeTimer; } + } - public byte[] ParameterData - { - get { return _parameterData; } - set - { - if (_parameterData == value) - return; - - valueCache = null; - - if (value == null) - _parameterData = Array.Empty(); - else - { - if (value.Length > 255 - 24) throw new ArgumentException("ParameterData to large!"); - _parameterData = value; - } + public byte PDL + { + get + { + switch (ResponseType) + { + case ERDM_ResponseType.NACK_REASON: + case ERDM_ResponseType.ACK_TIMER: + case ERDM_ResponseType.ACK_TIMER_HI_RES: + return 2; } + return (byte)ParameterData.Length; } + } - public ushort Checksum + public byte[] ParameterData + { + get { - get + switch (this.ResponseType) { - int sum = 0xCC + 0x01; //Start Code and Sub Start Code - sum += MessageLength; - - sum += SourceUID.ToBytes().Sum(c => (int)c); - sum += DestUID.ToBytes().Sum(c => (int)c); - - sum += TransactionCounter; - sum += PortID_or_Responsetype; - sum += MessageCounter; - sum += ((ushort)SubDevice) & 0xFF; - sum += (((ushort)SubDevice) >> 8) & 0xFF; - sum += (byte)Command; - ushort para = (ushort)Parameter; - sum += para & 0xFF; - sum += (para >> 8) & 0xFF; - sum += PDL; - foreach (byte b in ParameterData) - sum += b; - - return (ushort)(sum % 0x10000); + case ERDM_ResponseType.NACK_REASON: + return Tools.ValueToData(_nackReason); + case ERDM_ResponseType.ACK_TIMER: + case ERDM_ResponseType.ACK_TIMER_HI_RES: + return Tools.ValueToData(_acknowledgeTimer); } - } - public ushort? DeserializedChecksum1 - { - get; - private set; - } - public ushort? DeserializedChecksum2 - { - get; - private set; + return _parameterData; } - public bool ChecksumValid - { - get + set + { + if (_parameterData == value) + return; + + valueCache = null; + + if (value == null) + _parameterData = Array.Empty(); + else { - return DeserializedChecksum1 == DeserializedChecksum2; - } + if (value.Length > 255 - 24) throw new ArgumentException("ParameterData to large!"); + _parameterData = value; + } } + } - public ERDM_ResponseType? ResponseType + public ushort Checksum + { + get { - get - { - if (this.Command.HasFlag(ERDM_Command.RESPONSE)) - return (ERDM_ResponseType)PortID_or_Responsetype; - return null; - } + int sum = 0xCC + 0x01; //Start Code and Sub Start Code + sum += MessageLength; + + sum += SourceUID.ToBytes().Sum(c => (int)c); + sum += DestUID.ToBytes().Sum(c => (int)c); + + sum += TransactionCounter; + sum += PortID_or_Responsetype; + sum += ControllerFlags_or_MessageCounter; + sum += ((ushort)SubDevice) & 0xFF; + sum += (((ushort)SubDevice) >> 8) & 0xFF; + sum += (byte)Command; + ushort para = (ushort)Parameter; + sum += para & 0xFF; + sum += (para >> 8) & 0xFF; + sum += PDL; + foreach (byte b in ParameterData) + sum += b; + + return (ushort)(sum % 0x10000); + } + } + public ushort? DeserializedChecksum1 + { + get; + private set; + } + public ushort? DeserializedChecksum2 + { + get; + private set; + } + public bool ChecksumValid + { + get + { + return DeserializedChecksum1 == DeserializedChecksum2; } - public byte? PortID + } + + public ERDM_ResponseType? ResponseType + { + get { - get - { - if (!this.Command.HasFlag(ERDM_Command.RESPONSE)) - return PortID_or_Responsetype; - return null; - } + if (this.Command.HasFlag(ERDM_Command.RESPONSE)) + return (ERDM_ResponseType)PortID_or_Responsetype; + return null; + } + } + public byte? PortID + { + get + { + if (!this.Command.HasFlag(ERDM_Command.RESPONSE)) + return PortID_or_Responsetype; + return null; } + } - public bool IsAck + public bool IsAck + { + get { - get - { - if (!ResponseType.HasValue) - return false; - - ERDM_ResponseType resp = ResponseType.Value; - return - resp == ERDM_ResponseType.ACK || - resp == ERDM_ResponseType.ACK_OVERFLOW || - resp == ERDM_ResponseType.ACK_TIMER || - resp == ERDM_ResponseType.ACK_TIMER_HI_RES; - } + if (!ResponseType.HasValue) + return false; + + ERDM_ResponseType resp = ResponseType.Value; + return + resp == ERDM_ResponseType.ACK || + resp == ERDM_ResponseType.ACK_OVERFLOW || + resp == ERDM_ResponseType.ACK_TIMER || + resp == ERDM_ResponseType.ACK_TIMER_HI_RES; } + } - public byte[] BuildMessage() + public byte[] BuildMessage() + { + List ret = null; + switch (Command) { - List ret = null; - switch (Command) - { - case ERDM_Command.DISCOVERY_COMMAND_RESPONSE when Parameter == ERDM_Parameter.DISC_UNIQUE_BRANCH: - - byte preamble = preambleCount ?? 7; - if (preamble > 7) throw new ArgumentOutOfRangeException("preambleCount has to be within 0 and 7"); - ret = new List(preamble + 17); - for (int i = 0; i < preamble; i++) - ret.Add(0xFE); - ret.Add(0xAA); - var uidBytes = ((byte[])SourceUID); - for (int b = 0; b < uidBytes.Length; b++) - { - ret.Add((byte)(uidBytes[b] | 0xAA)); - ret.Add((byte)(uidBytes[b] | 0x55)); - } - ushort cs = (ushort)ret.Skip(preamble + 1).Take(12).Sum(c => c); - ret.Add((byte)((cs >> 8) | 0xAA)); - ret.Add((byte)((cs >> 8) | 0x55)); - ret.Add((byte)((cs & 0xFF) | 0xAA)); - ret.Add((byte)((cs & 0xFF) | 0x55)); - return ret.ToArray(); - default: - ret = new List(MessageLength + 2) - { - 0xcc, 0x01, MessageLength - }; - ret.AddRange(DestUID.ToBytes()); - ret.AddRange(SourceUID.ToBytes()); - ret.Add(TransactionCounter); - ret.Add(PortID_or_Responsetype); - ret.Add(MessageCounter); - ret.Add((byte)(((ushort)SubDevice) >> 8)); - ret.Add((byte)SubDevice); - ret.Add((byte)Command); - - ushort para = (ushort)Parameter; - ret.Add((byte)(para >> 8)); - ret.Add((byte)para); - ret.Add(PDL); - ret.AddRange(ParameterData); - - ret.Add((byte)(Checksum >> 8)); - ret.Add((byte)Checksum); - - return ret.ToArray(); - } + case ERDM_Command.DISCOVERY_COMMAND_RESPONSE when Parameter == ERDM_Parameter.DISC_UNIQUE_BRANCH: + + byte preamble = preambleCount ?? 7; + if (preamble > 7) throw new ArgumentOutOfRangeException("preambleCount has to be within 0 and 7"); + ret = new List(preamble + 17); + for (int i = 0; i < preamble; i++) + ret.Add(0xFE); + ret.Add(0xAA); + var uidBytes = ((byte[])SourceUID); + for (int b = 0; b < uidBytes.Length; b++) + { + ret.Add((byte)(uidBytes[b] | 0xAA)); + ret.Add((byte)(uidBytes[b] | 0x55)); + } + ushort cs = (ushort)ret.Skip(preamble + 1).Take(12).Sum(c => c); + ret.Add((byte)((cs >> 8) | 0xAA)); + ret.Add((byte)((cs >> 8) | 0x55)); + ret.Add((byte)((cs & 0xFF) | 0xAA)); + ret.Add((byte)((cs & 0xFF) | 0x55)); + return ret.ToArray(); + default: + ret = new List(MessageLength + 2) + { + 0xcc, 0x01, MessageLength + }; + ret.AddRange(DestUID.ToBytes()); + ret.AddRange(SourceUID.ToBytes()); + ret.Add(TransactionCounter); + ret.Add(PortID_or_Responsetype); + ret.Add(ControllerFlags_or_MessageCounter); + ret.Add((byte)(((ushort)SubDevice) >> 8)); + ret.Add((byte)SubDevice); + ret.Add((byte)Command); + + ushort para = (ushort)Parameter; + ret.Add((byte)(para >> 8)); + ret.Add((byte)para); + ret.Add(PDL); + ret.AddRange(ParameterData); + + ret.Add((byte)(Checksum >> 8)); + ret.Add((byte)Checksum); + + return ret.ToArray(); } + } - private object valueCache = null; - [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2200:Erneut ausführen, um Stapeldetails beizubehalten", Justification = "")] - public object Value + private object valueCache = null; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2200:Erneut ausführen, um Stapeldetails beizubehalten", Justification = "")] + public object Value + { + get { - get + try { - try + switch (this.ResponseType) { - if (this.ResponseType == ERDM_ResponseType.ACK_TIMER) - return valueCache = AcknowledgeTimer.FromPayloadData(this.ParameterData); - if (this.ResponseType == ERDM_ResponseType.ACK_TIMER_HI_RES) - return valueCache = AcknowledgeTimerHighRes.FromPayloadData(this.ParameterData); - if (this.Parameter == ERDM_Parameter.DISC_UNIQUE_BRANCH && this.Command == ERDM_Command.DISCOVERY_COMMAND) - return valueCache = DiscUniqueBranchRequest.FromPayloadData(this.ParameterData); - if (this.Parameter == ERDM_Parameter.DISC_MUTE && this.Command == ERDM_Command.DISCOVERY_COMMAND_RESPONSE) - return valueCache = DiscMuteUnmuteResponse.FromPayloadData(this.ParameterData); - if (this.Parameter == ERDM_Parameter.DISC_UN_MUTE && this.Command == ERDM_Command.DISCOVERY_COMMAND_RESPONSE) - return valueCache = DiscMuteUnmuteResponse.FromPayloadData(this.ParameterData); - - if (this.ParameterData?.Length == 0) - return valueCache = null; - - ushort manufacturer = 0; - if (this.Command.HasFlag(ERDM_Command.RESPONSE)) - manufacturer = SourceUID.ManufacturerID; - else - manufacturer = DestUID.ManufacturerID; - - var parameterBag = new ParameterBag(this.Parameter, manufacturer); - var define = MetadataFactory.GetDefine(parameterBag); - var cd = Tools.ConvertCommandDublicateToCommand(Command); - Metadata.JSON.Command? cmd = null; - if ((this.ParameterData?.Length ?? 0) == 0) + case ERDM_ResponseType.NACK_REASON: + case ERDM_ResponseType.ACK_TIMER: + case ERDM_ResponseType.ACK_TIMER_HI_RES: return null; + } + if (this.Parameter == ERDM_Parameter.DISC_UNIQUE_BRANCH && this.Command == ERDM_Command.DISCOVERY_COMMAND) + return valueCache = DiscUniqueBranchRequest.FromPayloadData(this.ParameterData); + if (this.Parameter == ERDM_Parameter.DISC_MUTE && this.Command == ERDM_Command.DISCOVERY_COMMAND_RESPONSE) + return valueCache = DiscMuteUnmuteResponse.FromPayloadData(this.ParameterData); + if (this.Parameter == ERDM_Parameter.DISC_UN_MUTE && this.Command == ERDM_Command.DISCOVERY_COMMAND_RESPONSE) + return valueCache = DiscMuteUnmuteResponse.FromPayloadData(this.ParameterData); - if (define is null) - return null; + if (this.ParameterData?.Length == 0) + return valueCache = null; + + ushort manufacturer = 0; + if (this.Command.HasFlag(ERDM_Command.RESPONSE)) + manufacturer = SourceUID.ManufacturerID; + else + manufacturer = DestUID.ManufacturerID; + + var parameterBag = new ParameterBag(this.Parameter, manufacturer); + var define = MetadataFactory.GetDefine(parameterBag); + var cd = Tools.ConvertCommandDublicateToCommand(Command); + Metadata.JSON.Command? cmd = null; + if ((this.ParameterData?.Length ?? 0) == 0) + return null; - try - { - define.GetCommand(cd, out cmd); - if (cmd is null || !cmd.HasValue) - return null; - if(cmd.Value.GetIsEmpty()) - return null; - return valueCache = MetadataFactory.ParseDataToPayload(define, cd, this.ParameterData).ParsedObject; - } - catch (Exception ex) - { - StringBuilder b = new StringBuilder(128); - b.AppendLine("Dest: " + DestUID); - b.AppendLine("Source: " + SourceUID); - b.AppendLine("Transaction: " + TransactionCounter); - b.AppendLine("MessageCounter: " + MessageCounter); - if (ResponseType.HasValue) - b.AppendLine("Responsetype: " + ResponseType); - if (PortID.HasValue) - b.AppendLine("PortID: " + PortID); - b.AppendLine("SubDevice: " + SubDevice); - b.AppendLine("Command: " + Command); - b.AppendLine("Parameter: " + ((ERDM_Parameter)Parameter).ToString()); - Logger?.LogError(ex,$"Message: {b.ToString()}"); - throw ex; - } + if (define is null) + return null; + + try + { + define.GetCommand(cd, out cmd); + if (cmd is null || !cmd.HasValue) + return null; + if (cmd.Value.GetIsEmpty()) + return null; + return valueCache = MetadataFactory.ParseDataToPayload(define, cd, this.ParameterData).ParsedObject; } catch (Exception ex) { - Logger?.LogError(ex); + StringBuilder b = new StringBuilder(128); + b.AppendLine("Dest: " + DestUID); + b.AppendLine("Source: " + SourceUID); + b.AppendLine("Transaction: " + TransactionCounter); + b.AppendLine("MessageCounter: " + MessageCounter); + if (ResponseType.HasValue) + b.AppendLine("Responsetype: " + ResponseType); + if (PortID.HasValue) + b.AppendLine("PortID: " + PortID); + b.AppendLine("SubDevice: " + SubDevice); + b.AppendLine("Command: " + Command); + b.AppendLine("Parameter: " + ((ERDM_Parameter)Parameter).ToString()); + Logger?.LogError(ex, $"Message: {b.ToString()}"); throw ex; } } - } + catch (Exception ex) + { + Logger?.LogError(ex); + throw ex; + } + } + } - public override string ToString() - { - StringBuilder b = new StringBuilder(128); - b.AppendLine("Dest: " + DestUID); - b.AppendLine("Source: " + SourceUID); - b.AppendLine("Transaction: " + TransactionCounter); - b.AppendLine("MessageCounter: " + MessageCounter); - if (ResponseType.HasValue) - b.AppendLine("Responsetype: " + ResponseType); - if (PortID.HasValue) - b.AppendLine("PortID: " + PortID); - b.AppendLine("SubDevice: " + SubDevice); - b.AppendLine("Command: " + Command); - b.AppendLine("Parameter: " + ((ERDM_Parameter)Parameter).ToString()); - if ( - Command == ERDM_Command.GET_COMMAND_RESPONSE || - Command == ERDM_Command.SET_COMMAND || - Command == ERDM_Command.SET_COMMAND_RESPONSE || - Command.HasFlag(ERDM_Command.DISCOVERY_COMMAND)) + public override string ToString() + { + StringBuilder b = new StringBuilder(128); + b.AppendLine("Dest: " + DestUID); + b.AppendLine("Source: " + SourceUID); + b.AppendLine("Transaction: " + TransactionCounter); + b.AppendLine("MessageCounter: " + MessageCounter); + if (ResponseType.HasValue) + b.AppendLine("Responsetype: " + ResponseType); + if (PortID.HasValue) + b.AppendLine("PortID: " + PortID); + b.AppendLine("SubDevice: " + SubDevice); + b.AppendLine("Command: " + Command); + b.AppendLine("Parameter: " + ((ERDM_Parameter)Parameter).ToString()); + if ( + Command == ERDM_Command.GET_COMMAND_RESPONSE || + Command == ERDM_Command.SET_COMMAND || + Command == ERDM_Command.SET_COMMAND_RESPONSE || + Command.HasFlag(ERDM_Command.DISCOVERY_COMMAND)) + { + object val = null; + try + { + val = this.Value; + } + catch { - object val = null; - try - { - val = this.Value; - } - catch - { - } - if (val != null) - b.AppendLine("Value: " + valueString()); + } + if (val != null) + b.AppendLine("Value: " + valueString()); - string valueString() + string valueString() + { + string value; + if (val is Array array) { - string value; - 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 (val is string str) - value = $"\"{str}\""; - else - value = Value?.ToString() ?? "[NULL]"; - if (value.Contains(Environment.NewLine) && !value.StartsWith(Environment.NewLine)) - { - value = Environment.NewLine + value; - value = value.Replace(Environment.NewLine, Environment.NewLine + "\t"); - } - return value; + List list = new List(); + foreach (var a in array) + list.Add(a.ToString()); + value = string.Join("," + Environment.NewLine, list); } - } - //Add More if required + else if (val is string str) + value = $"\"{str}\""; + else + value = Value?.ToString() ?? "[NULL]"; + if (value.Contains(Environment.NewLine) && !value.StartsWith(Environment.NewLine)) + { + value = Environment.NewLine + value; + value = value.Replace(Environment.NewLine, Environment.NewLine + "\t"); + } + return value; + } + } + //Add More if required - return b.ToString(); - } + return b.ToString(); + } - public override bool Equals(object obj) - { - return Equals(obj as RDMMessage); - } + public override bool Equals(object obj) + { + return Equals(obj as RDMMessage); + } - public bool Equals(RDMMessage other) - { - bool res = other is not null && - MessageLength == other.MessageLength && - SourceUID.Equals(other.SourceUID) && - DestUID.Equals(other.DestUID) && - TransactionCounter == other.TransactionCounter && - PortID_or_Responsetype == other.PortID_or_Responsetype && - MessageCounter == other.MessageCounter && - SubDevice.Equals(other.SubDevice) && - Command == other.Command && - Parameter == other.Parameter && - EqualityComparer.Default.Equals(NackReason, other.NackReason) && - PDL == other.PDL && - ParameterData.SequenceEqual(other.ParameterData) && - Checksum == other.Checksum && - ChecksumValid == other.ChecksumValid && - ResponseType == other.ResponseType && - IsAck == other.IsAck && - preambleCount == other.preambleCount; - return res; - } - public override int GetHashCode() + public bool Equals(RDMMessage other) + { + bool res = other is not null && + MessageLength == other.MessageLength && + SourceUID.Equals(other.SourceUID) && + DestUID.Equals(other.DestUID) && + TransactionCounter == other.TransactionCounter && + PortID_or_Responsetype == other.PortID_or_Responsetype && + MessageCounter == other.MessageCounter && + SubDevice.Equals(other.SubDevice) && + Command == other.Command && + Parameter == other.Parameter && + NackReason == other.NackReason && + PDL == other.PDL && + ParameterData.SequenceEqual(other.ParameterData) && + Checksum == other.Checksum && + ChecksumValid == other.ChecksumValid && + ResponseType == other.ResponseType && + IsAck == other.IsAck && + preambleCount == other.preambleCount; + return res; + } + public override int GetHashCode() + { + unchecked { - unchecked - { - var bytes = BuildMessage(); - var result = 0; - foreach (byte b in bytes) - result = (result * 31) ^ b; - return result; - } + var bytes = BuildMessage(); + var result = 0; + foreach (byte b in bytes) + result = (result * 31) ^ b; + return result; } - } + } } diff --git a/RDMSharp/RDM/RDMMessageInvalidException.cs b/RDMSharp/RDM/RDMMessageInvalidException.cs index 34ee622..e258847 100644 --- a/RDMSharp/RDM/RDMMessageInvalidException.cs +++ b/RDMSharp/RDM/RDMMessageInvalidException.cs @@ -1,44 +1,47 @@ using System; using System.Linq; -namespace RDMSharp +namespace RDMSharp; + +public class RDMMessageInvalidException : Exception { - public class RDMMessageInvalidException : Exception + public readonly RDMMessage RDMMessage; + protected RDMMessageInvalidException(RDMMessage rdmMessage, string message) : base(message) + { + RDMMessage = rdmMessage; + } + internal static void ThrowIfInvalid(RDMMessage msg, ERDM_Command expectedCommand, params ERDM_Parameter[] expectedParameters) { - public readonly RDMMessage RDMMessage; - protected RDMMessageInvalidException(RDMMessage rdmMessage, string message) : base(message) - { - RDMMessage = rdmMessage; - } - internal static void ThrowIfInvalid(RDMMessage msg, ERDM_Command expectedCommand, params ERDM_Parameter[] expectedParameters) - { #if NETSTANDARD - if (msg == null) - throw new ArgumentNullException($"Argument {nameof(msg)} can't be null"); + if (msg == null) + throw new ArgumentNullException($"Argument {nameof(msg)} can't be null"); #else - ArgumentNullException.ThrowIfNull(msg); + ArgumentNullException.ThrowIfNull(msg); #endif - if (expectedCommand.HasFlag(ERDM_Command.RESPONSE) && !msg.IsAck) throw new RDMMessageInvalidException(msg, $"NACK Reason: {(ERDM_NackReason)msg.ParameterData[0]}"); - if (msg.Command != expectedCommand) throw new RDMMessageInvalidException(msg, $"Command is not the expected Command: {expectedCommand}"); - if (expectedParameters.Length != 0 && !expectedParameters.Contains(msg.Parameter)) throw new RDMMessageInvalidException(msg, $"Parameter is not one of the expected Parameters: {string.Join(";", expectedParameters)}"); - } - internal static void ThrowIfInvalidPDL(RDMMessage msg, ERDM_Command expectedCommand, ERDM_Parameter expectedParameter, params int[] expectedPDL) - { - ThrowIfInvalid(msg, expectedCommand, expectedParameter); - if (!expectedPDL.Contains(msg.PDL)) throw new RDMMessageInvalidException(msg, $"PayloadDataLength is fitting the given Values {string.Join(";", expectedPDL)}"); - } - internal static void ThrowIfInvalidPDL(RDMMessage msg, ERDM_Command expectedCommand, ERDM_Parameter[] expectedParameters, params int[] expectedPDL) + if (expectedCommand.HasFlag(ERDM_Command.RESPONSE) && !msg.IsAck) { - ThrowIfInvalid(msg, expectedCommand, expectedParameters); - RDMMessageInvalidPDLException.ThrowIfInvalidPDL(msg, expectedPDL); - RDMMessageInvalidPDLException.ThrowIfInvalidPDL(msg.ParameterData, expectedPDL); - } - internal static void ThrowIfInvalidPDLRange(RDMMessage msg, ERDM_Command expectedCommand, ERDM_Parameter expectedParameter, int expectedMinPDL, int expectedMaxPDL) - { - ThrowIfInvalid(msg, expectedCommand, expectedParameter); - RDMMessageInvalidPDLException.ThrowIfInvalidPDLRange(msg, expectedMinPDL, expectedMaxPDL); - RDMMessageInvalidPDLException.ThrowIfInvalidPDLRange(msg.ParameterData, expectedMinPDL, expectedMaxPDL); + byte[] data = msg.ParameterData.ToArray(); + throw new RDMMessageInvalidException(msg, $"NACK Reason: {Tools.DataToEnum(ref data)}"); } + if (msg.Command != expectedCommand) throw new RDMMessageInvalidException(msg, $"Command is not the expected Command: {expectedCommand}"); + if (expectedParameters.Length != 0 && !expectedParameters.Contains(msg.Parameter)) throw new RDMMessageInvalidException(msg, $"Parameter is not one of the expected Parameters: {string.Join(";", expectedParameters)}"); + } + internal static void ThrowIfInvalidPDL(RDMMessage msg, ERDM_Command expectedCommand, ERDM_Parameter expectedParameter, params int[] expectedPDL) + { + ThrowIfInvalid(msg, expectedCommand, expectedParameter); + if (!expectedPDL.Contains(msg.PDL)) throw new RDMMessageInvalidException(msg, $"PayloadDataLength is fitting the given Values {string.Join(";", expectedPDL)}"); + } + internal static void ThrowIfInvalidPDL(RDMMessage msg, ERDM_Command expectedCommand, ERDM_Parameter[] expectedParameters, params int[] expectedPDL) + { + ThrowIfInvalid(msg, expectedCommand, expectedParameters); + RDMMessageInvalidPDLException.ThrowIfInvalidPDL(msg, expectedPDL); + RDMMessageInvalidPDLException.ThrowIfInvalidPDL(msg.ParameterData, expectedPDL); + } + internal static void ThrowIfInvalidPDLRange(RDMMessage msg, ERDM_Command expectedCommand, ERDM_Parameter expectedParameter, int expectedMinPDL, int expectedMaxPDL) + { + ThrowIfInvalid(msg, expectedCommand, expectedParameter); + RDMMessageInvalidPDLException.ThrowIfInvalidPDLRange(msg, expectedMinPDL, expectedMaxPDL); + RDMMessageInvalidPDLException.ThrowIfInvalidPDLRange(msg.ParameterData, expectedMinPDL, expectedMaxPDL); } } \ No newline at end of file diff --git a/RDMSharp/RDM/RequestResponseHistoryEntry.cs b/RDMSharp/RDM/RequestResponseHistoryEntry.cs new file mode 100644 index 0000000..3224837 --- /dev/null +++ b/RDMSharp/RDM/RequestResponseHistoryEntry.cs @@ -0,0 +1,73 @@ +using System; +using System.ComponentModel; + +namespace RDMSharp; + +public class RequestResponseHistoryEntry : INotifyPropertyChanged +{ + public readonly DateTime Timestamp = DateTime.Now; + public readonly RDMMessage Request; + + private DateTime? _timestampRespone; + public DateTime? TimestampResponse + { + get + { + return _timestampRespone; + } + private set + { + if (_timestampRespone == value) + return; + _timestampRespone = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TimestampResponse))); + } + } + + private RDMMessage _response; + public RDMMessage Response + { + get + { + return _response; + } + private set + { + if (_response == value) + return; + _response = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Response))); + } + } + + private string _state; + public string State + { + get + { + return _state; + } + private set + { + if (_state == value) + return; + _state = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(State))); + } + } + + + public event PropertyChangedEventHandler PropertyChanged; + + public RequestResponseHistoryEntry(RDMMessage request) + { + Request = request; + } + + internal void SetResponse(RDMMessage response, string state = "Success") + { + Response = response; + TimestampResponse = DateTime.Now; + State = state; + } +} \ No newline at end of file diff --git a/RDMSharp/RDM/RequestResult.cs b/RDMSharp/RDM/RequestResult.cs index cd40d0d..0b0ddd4 100644 --- a/RDMSharp/RDM/RequestResult.cs +++ b/RDMSharp/RDM/RequestResult.cs @@ -1,30 +1,31 @@ using System; -namespace RDMSharp +namespace RDMSharp; + +public readonly struct RequestResult { - public readonly struct RequestResult - { - public readonly RDMMessage Request; - public readonly RDMMessage Response; - public readonly bool Success; - public readonly bool Cancel; - public readonly TimeSpan? ElapsedTime; + public readonly RDMMessage Request; + public readonly RDMMessage Response; + public readonly bool Success; + public readonly bool Timeout; + public readonly bool Disposing; + public readonly TimeSpan? ElapsedTime; - public RequestResult(in RDMMessage request, in bool cancle = false) - { - Request = request; - Response = null; - Success = false; - Cancel = cancle; - ElapsedTime = null; - } + public RequestResult(in RDMMessage request, in bool timeout = false, in bool disposing = false) + { + Request = request; + Response = null; + Success = false; + Timeout = timeout; + Disposing = disposing; + ElapsedTime = null; + } - public RequestResult(in RDMMessage request, in RDMMessage response, TimeSpan elapsedTime) - { - Request = request; - Response = response; - Success = true; - ElapsedTime = elapsedTime; - } + public RequestResult(in RDMMessage request, in RDMMessage response, TimeSpan elapsedTime) + { + Request = request; + Response = response; + Success = true; + ElapsedTime = elapsedTime; } } \ No newline at end of file diff --git a/RDMSharp/RDM/Sensor.cs b/RDMSharp/RDM/Sensor.cs index 4c57bba..308ed6b 100644 --- a/RDMSharp/RDM/Sensor.cs +++ b/RDMSharp/RDM/Sensor.cs @@ -25,6 +25,7 @@ private set this.PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(Type))); } } + public readonly RDMSensorTypeCustomDefine CustomType; private ERDM_SensorUnit unit; public ERDM_SensorUnit Unit @@ -39,6 +40,7 @@ private set this.PropertyChanged?.InvokeFailSafe(this, new PropertyChangedEventArgs(nameof(Unit))); } } + public readonly RDMSensorUnitCustomDefine CustomUnit; private ERDM_UnitPrefix prefix; public ERDM_UnitPrefix Prefix @@ -218,7 +220,9 @@ internal protected Sensor(in byte sensorId, in short normalMinimum, in short normalMaximum, in bool lowestHighestValueSupported = false, - in bool recordedValueSupported = false) : this(sensorId) + in bool recordedValueSupported = false, + in RDMSensorUnitCustomDefine customUnit = null, + in RDMSensorTypeCustomDefine customType = null) : this(sensorId) { if (String.IsNullOrWhiteSpace(description)) throw new ArgumentNullException(nameof(description)); @@ -233,6 +237,20 @@ internal protected Sensor(in byte sensorId, NormalMaximum = normalMaximum; LowestHighestValueSupported = lowestHighestValueSupported; RecordedValueSupported = recordedValueSupported; + CustomUnit = customUnit; + CustomType = customType; + + if ((byte)Unit >= 0x80 && customUnit is null) + throw new ArgumentException($"The given {nameof(unit)} is a custom unit but no {nameof(customUnit)} is given.", nameof(unit)); + + if ((byte)Type >= 0x80 && customType is null) + throw new ArgumentException($"The given {nameof(type)} is a custom type but no {nameof(customType)} is given.", nameof(type)); + + if (customUnit is not null && customUnit.Id != (byte)Unit) + throw new ArgumentException($"The given {nameof(customUnit)} does not match the given {nameof(unit)}.", nameof(customUnit)); + + if (customType is not null && customType.Id != (byte)Type) + throw new ArgumentException($"The given {nameof(customType)} does not match the given {nameof(type)}.", nameof(customType)); } public Sensor(in byte sensorId, in short initValue, @@ -245,7 +263,9 @@ public Sensor(in byte sensorId, in short normalMinimum, in short normalMaximum, in bool lowestHighestValueSupported = false, - in bool recordedValueSupported = false) : this( + in bool recordedValueSupported = false, + in RDMSensorUnitCustomDefine customUnit = null, + in RDMSensorTypeCustomDefine customType = null) : this( sensorId, type, unit, @@ -256,7 +276,9 @@ public Sensor(in byte sensorId, normalMinimum, normalMaximum, lowestHighestValueSupported, - recordedValueSupported) + recordedValueSupported, + customUnit, + customType) { this.UpdateValue(initValue); if (LowestHighestValueSupported) diff --git a/RDMSharp/RDM/Tools.cs b/RDMSharp/RDM/Tools.cs index fbd2ada..a90f58d 100644 --- a/RDMSharp/RDM/Tools.cs +++ b/RDMSharp/RDM/Tools.cs @@ -125,7 +125,7 @@ public static string GetUnitSymbol(this ERDM_SensorUnit unit) public static string GetStatusMessage(this ERDM_StatusMessage status, in short dataValue1 = 0, in short dataValue2 = 0) { - return status.GetAttribute().GetFormatedString(dataValue1, dataValue2) ?? string.Empty; + return status.GetAttribute()?.GetFormatedString(dataValue1, dataValue2) ?? string.Empty; } public static string GetEnumDescription(Enum value) { diff --git a/RDMSharp/RDMSharp.cs b/RDMSharp/RDMSharp.cs index 9cfd1bd..62c571c 100644 --- a/RDMSharp/RDMSharp.cs +++ b/RDMSharp/RDMSharp.cs @@ -1,106 +1,124 @@ using System; using System.Collections.Concurrent; +using System.Threading; using System.Threading.Tasks; -namespace RDMSharp +namespace RDMSharp; + +public class RDMSharp { - public class RDMSharp + private static RDMSharp _instance; + public static RDMSharp Instance { - private static RDMSharp _instance; - public static RDMSharp Instance + get { - get - { - return _instance; - } + return _instance; } + } - public readonly UID ControllerUID; - public readonly Func SendMessage; - public readonly AsyncRDMRequestHelper AsyncRDMRequestHelper; - public event EventHandler? ResponseReceivedEvent; - public event EventHandler? RequestReceivedEvent; + public readonly UID ControllerUID; + public readonly Func SendMessage; + public readonly AsyncRDMRequestHelper AsyncRDMRequestHelper; + public event EventHandler? ResponseReceivedEvent; + public event EventHandler? RequestReceivedEvent; - private readonly ConcurrentDictionary transactionCounters = new ConcurrentDictionary(); + private readonly ConcurrentDictionary transactionCounters = new ConcurrentDictionary(); + private readonly ConcurrentDictionary transactionLock = new ConcurrentDictionary(); - private RDMSharp(UID controllerUID, Func sendMessage) - { - _instance = this ?? throw new InvalidOperationException("RDMSharp instance already exists. Use Instance property to access it."); + private RDMSharp(UID controllerUID, Func sendMessage) + { + _instance = this ?? throw new InvalidOperationException("RDMSharp instance already exists. Use Instance property to access it."); - this.ControllerUID = controllerUID; + this.ControllerUID = controllerUID; - SendMessage = sendMessage ?? throw new ArgumentNullException(nameof(sendMessage), "SendMethode can't be null."); - AsyncRDMRequestHelper = new AsyncRDMRequestHelper(async (rdmMessage) => - { - rdmMessage.SourceUID = ControllerUID; - await SendMessage.Invoke(rdmMessage); - }); - } - public void ResponseReceived(RDMMessage rdmMessage) + SendMessage = sendMessage ?? throw new ArgumentNullException(nameof(sendMessage), "SendMethode can't be null."); + AsyncRDMRequestHelper = new AsyncRDMRequestHelper(async (rdmMessage) => { - if (!AsyncRDMRequestHelper.ReceiveMessage(rdmMessage)) - ResponseReceivedEvent?.InvokeFailSafe(this, rdmMessage); - } - public bool RequestReceived(RDMMessage request, out RDMMessage response) - { - RDMMessage _response = null; - var e = new RequestReceivedEventArgs(request); - var handlers = RequestReceivedEvent?.GetInvocationList() ?? Array.Empty(); + rdmMessage.SourceUID = ControllerUID; + await SendMessage.Invoke(rdmMessage); + }); + } + public void ResponseReceived(RDMMessage rdmMessage) + { + if (!AsyncRDMRequestHelper.ReceiveMessage(rdmMessage)) + ResponseReceivedEvent?.InvokeFailSafe(this, rdmMessage); + } + public bool RequestReceived(RDMMessage request, out RDMMessage response) + { + RDMMessage _response = null; + var e = new RequestReceivedEventArgs(request); + var handlers = RequestReceivedEvent?.GetInvocationList() ?? Array.Empty(); - // Parallel ausführen, aber Reihenfolge der Responses beachten - ParallelOptions parallelOptions = new ParallelOptions - { - MaxDegreeOfParallelism = Environment.ProcessorCount // Optional: Setze die maximale Parallelität - }; - Parallel.ForEach(handlers, parallelOptions, (handler, state) => + // Parallel ausführen, aber Reihenfolge der Responses beachten + ParallelOptions parallelOptions = new ParallelOptions + { + MaxDegreeOfParallelism = Environment.ProcessorCount // Optional: Setze die maximale Parallelität + }; + Parallel.ForEach(handlers, parallelOptions, (handler, state) => + { + handler.InvokeFailSafe(this, e); + if (e.Response is not null) { - handler.InvokeFailSafe(this, e); - if (e.Response is not null) + if (request.Command != ERDM_Command.DISCOVERY_COMMAND || request.DestUID.IsBroadcast) { - if (request.Command != ERDM_Command.DISCOVERY_COMMAND || request.DestUID.IsBroadcast) - { - _response = e.Response; - state.Stop(); // Beende Parallel.ForEach, wenn eine Response gefunden wurde - } + _response = e.Response; + state.Stop(); // Beende Parallel.ForEach, wenn eine Response gefunden wurde } - }); + } + }); - response = _response; - return response is not null; - } + response = _response; + return response is not null; + } - public static void Initialize(UID controllerUID, Func sendMethode) + public static void Initialize(UID controllerUID, Func sendMethode) + { + if (_instance != null) { - if (_instance != null) - { - throw new InvalidOperationException("RDMSharp instance already exists. Use Instance property to access it."); - } - _instance = new RDMSharp(controllerUID, sendMethode); + throw new InvalidOperationException("RDMSharp instance already exists. Use Instance property to access it."); } + _instance = new RDMSharp(controllerUID, sendMethode); + } - public class RequestReceivedEventArgs : EventArgs + public class RequestReceivedEventArgs : EventArgs + { + public RDMMessage Request { get; } + public RDMMessage Response { get; set; } + public RequestReceivedEventArgs(RDMMessage request) { - public RDMMessage Request { get; } - public RDMMessage Response { get; set; } - public RequestReceivedEventArgs(RDMMessage request) - { - Request = request ?? throw new ArgumentNullException(nameof(request), "Request can't be null."); - Response = null; - } + Request = request ?? throw new ArgumentNullException(nameof(request), "Request can't be null."); + Response = null; } - internal byte getTransactionCounter(UID uid) + } + internal byte getTransactionCounter(UID uid) + { + if (transactionCounters.TryGetValue(uid, out byte tc)) { - if (transactionCounters.TryGetValue(uid, out byte tc)) - { - tc++; - transactionCounters.AddOrUpdate(uid, (a) => tc, (b, c) => tc); - return tc; - } - else - { - transactionCounters.TryAdd(uid, 0); - return 0; - } + tc++; + transactionCounters.AddOrUpdate(uid, (a) => tc, (b, c) => tc); + return tc; + } + else + { + transactionCounters.TryAdd(uid, 0); + return 0; + } + } + internal Task lockTransaktion(UID uid) + { + if (!transactionLock.TryGetValue(uid, out SemaphoreSlim semaphore)) + { + semaphore = new SemaphoreSlim(1); + transactionLock.TryAdd(uid, semaphore); + } + + return semaphore.WaitAsync(); + } + internal void unlockTransaktion(UID uid) + { + if (transactionLock.TryGetValue(uid, out SemaphoreSlim? semaphore)) + { + semaphore.Release(); } } } \ No newline at end of file diff --git a/RDMSharp/RDMSharp.csproj b/RDMSharp/RDMSharp.csproj index 3422b47..d8c656c 100644 --- a/RDMSharp/RDMSharp.csproj +++ b/RDMSharp/RDMSharp.csproj @@ -1,7 +1,9 @@ - net6.0;net7.0;net8.0;net9.0 + net6.0;net7.0;net8.0;net9.0;net10.0 LICENSE.md + CC BY-NC 4.0 + https://creativecommons.org/licenses/by-nc/4.0/legalcode 0.0.14 https://github.com/DMXControl/RDMSharp $(RepositoryUrl) @@ -11,6 +13,7 @@ Icons\RDMSharp.ico This library abstracts the communication using RDM in C# and takes a lot of work off the developer, as well as enables a standardized use of RDM in C# DMXControl-Projects e.V. + DMXControl-Projects e.V. Patrick Grote $(AssemblyName) latest @@ -31,12 +34,12 @@ - - + + - - - + + + 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 index 3f6854e..45d3322 100644 --- 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 @@ -9,9 +9,7 @@ "set_request": [ { "name": "scene_num", - "type": "uint16", - "units": 21, - "prefixPower": -1 + "type": "uint16" }, { "name": "up_fade_time", 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 index 15feb96..4fae45b 100644 --- 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 @@ -1,6 +1,6 @@ { "name": "REAL_TIME_CLOCK", - "displayName": "Real TIme Clock", + "displayName": "Real Time Clock", "manufacturer_id": 0, "pid": 1539, "version": 1, 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 index cb1e97a..f0c50a9 100644 --- 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 @@ -4,15 +4,15 @@ "manufacturer_id": 0, "pid": 1620, "version": 1, - "set_request_subdevice_range": [ "root", "subdevices" ], - "set_request": [ + "get_request_subdevice_range": [ "root", "subdevices" ], + "get_request": [ { "name": "tag", "type": "string", "maxLength": 32 } ], - "set_response": [ + "get_response": [ { "name": "status", "type": "boolean", diff --git a/RDMSharpTests/Devices/Mock/AbstractMockGeneratedDevice.cs b/RDMSharpTests/Devices/Mock/AbstractMockGeneratedDevice.cs index 88aea7b..75c1db9 100644 --- a/RDMSharpTests/Devices/Mock/AbstractMockGeneratedDevice.cs +++ b/RDMSharpTests/Devices/Mock/AbstractMockGeneratedDevice.cs @@ -1,37 +1,14 @@ -namespace RDMSharpTests.Devices.Mock +using RDMSharp.RDM.Device.Module; + +namespace RDMSharpTests.Devices.Mock { internal abstract class AbstractMockGeneratedDevice : AbstractGeneratedRDMDevice { - - public new string SoftwareVersionLabel - { - get - { - return base.SoftwareVersionLabel; - } - internal set - { - base.SoftwareVersionLabel = value; - } - } - - - public new string BootSoftwareVersionLabel - { - get - { - return base.BootSoftwareVersionLabel; - } - internal set - { - base.BootSoftwareVersionLabel = value; - } - } - public AbstractMockGeneratedDevice(UID uid, ERDM_Parameter[] parameters, string manufacturer, Sensor[]? sensors = null, IRDMDevice[]? subDevices = null) : base(uid, parameters, manufacturer, sensors: sensors, subDevices: subDevices) + public AbstractMockGeneratedDevice(UID uid, IRDMDevice[]? subDevices = null, IReadOnlyCollection mudules = null) : base(uid, subDevices: subDevices, modules: mudules) { } - public AbstractMockGeneratedDevice(UID uid, SubDevice subDevice, ERDM_Parameter[] parameters, string manufacturer, Sensor[]? sensors = null) : base(uid, subDevice, parameters, manufacturer, sensors: sensors) + public AbstractMockGeneratedDevice(UID uid, SubDevice subDevice, IReadOnlyCollection mudules = null) : base(uid, subDevice, modules: mudules) { } internal RDMMessage? ProcessRequestMessage_Internal(RDMMessage request) @@ -39,25 +16,17 @@ public AbstractMockGeneratedDevice(UID uid, SubDevice subDevice, ERDM_Parameter[ return base.processRequestMessage(request); } - internal new void AddStatusMessage(RDMStatusMessage statusMessage) - { - base.AddStatusMessage(statusMessage); - } - internal new void ClearStatusMessage(RDMStatusMessage statusMessage) - { - base.ClearStatusMessage(statusMessage); - } - internal new void RemoveStatusMessage(RDMStatusMessage statusMessage) + internal void AddStatusMessage(RDMStatusMessage statusMessage) { - base.RemoveStatusMessage(statusMessage); + base.statusMessageModule?.AddStatusMessage(statusMessage); } - internal new void AddSensors(params Sensor[] sensor) + internal void ClearStatusMessage(RDMStatusMessage statusMessage) { - base.AddSensors(sensor); + base.statusMessageModule?.ClearStatusMessage(statusMessage); } - internal new void RemoveSensors(params Sensor[] sensor) + internal void RemoveStatusMessage(RDMStatusMessage statusMessage) { - base.RemoveSensors(sensor); + base.statusMessageModule?.RemoveStatusMessage(statusMessage); } protected sealed override void onDispose() diff --git a/RDMSharpTests/Devices/Mock/MockGeneratedDevice1.cs b/RDMSharpTests/Devices/Mock/MockGeneratedDevice1.cs index 0516fae..be2d040 100644 --- a/RDMSharpTests/Devices/Mock/MockGeneratedDevice1.cs +++ b/RDMSharpTests/Devices/Mock/MockGeneratedDevice1.cs @@ -1,4 +1,6 @@ -namespace RDMSharpTests.Devices.Mock +using RDMSharp.RDM.Device.Module; + +namespace RDMSharpTests.Devices.Mock { internal class MockGeneratedDevice1 : AbstractMockGeneratedDevice { @@ -12,9 +14,6 @@ public override EManufacturer ManufacturerID public override ushort DeviceModelID => 20; public override ERDM_ProductCategoryCoarse ProductCategoryCoarse => ERDM_ProductCategoryCoarse.CONTROL; public override ERDM_ProductCategoryFine ProductCategoryFine => ERDM_ProductCategoryFine.DATA_CONVERSION; - public override uint SoftwareVersionID => 0x1234; - public override string DeviceModelDescription => "Test Model Description"; - public override bool SupportDMXAddress => true; private static readonly GeneratedPersonality[] PERSONALITYS = new GeneratedPersonality[] { new GeneratedPersonality(1, "5CH RGB", @@ -51,17 +50,26 @@ private static Sensor[] GetSensors() { new MockSensorVolt3_3(3, 331), new MockSensorVolt5(4, 498) }; } - public override GeneratedPersonality[] Personalities => PERSONALITYS; public override bool SupportQueued => true; - public override bool SupportStatus => true; - - public MockGeneratedDevice1(UID uid) : base(uid, SubDevice.Root, new ERDM_Parameter[] { ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL }, "Dummy Manufacturer 9FFF", GetSensors()) + public MockGeneratedDevice1(UID uid, IReadOnlyCollection modules = null) : base(uid, SubDevice.Root, GetModules().Concat(modules ?? Array.Empty()).ToList().AsReadOnly()) + { + } + private static IReadOnlyCollection GetModules() { - this.DeviceLabel = "Dummy Device 1"; - this.SoftwareVersionLabel = $"Dummy Software"; - this.BootSoftwareVersionLabel = $"Dummy Bootloader Software"; + return new IModule[] { + new DeviceLabelModule("Dummy Device 1"), + new ManufacturerLabelModule("Dummy Manufacturer 9FFF"), + new DeviceModelDescriptionModule("Test Model Description"), + new SoftwareVersionModule(1234, $"Dummy Software"), + new BootSoftwareVersionModule(123, $"Dummy Bootloader Software"), + new DMX_StartAddressModule(1), + new DMX_PersonalityModule(1,PERSONALITYS), + new SlotsModule(), + new SensorsModule(GetSensors()), + new StatusMessageModule() + }; } protected sealed override void OnDispose() { diff --git a/RDMSharpTests/Devices/Mock/MockGeneratedDeviceWithSubDevice1.cs b/RDMSharpTests/Devices/Mock/MockGeneratedDeviceWithSubDevice1.cs index 67f60ad..47d13aa 100644 --- a/RDMSharpTests/Devices/Mock/MockGeneratedDeviceWithSubDevice1.cs +++ b/RDMSharpTests/Devices/Mock/MockGeneratedDeviceWithSubDevice1.cs @@ -1,4 +1,6 @@ -namespace RDMSharpTests.Devices.Mock +using RDMSharp.RDM.Device.Module; + +namespace RDMSharpTests.Devices.Mock { internal abstract class MockGeneratedDeviceWithSubDevice1 : AbstractMockGeneratedDevice { @@ -6,26 +8,15 @@ internal abstract class MockGeneratedDeviceWithSubDevice1 : AbstractMockGenerate public override ushort DeviceModelID => 50; public override ERDM_ProductCategoryCoarse ProductCategoryCoarse => ERDM_ProductCategoryCoarse.DIMMER; public override ERDM_ProductCategoryFine ProductCategoryFine => ERDM_ProductCategoryFine.DIMMER_CS_LED; - public override uint SoftwareVersionID => 0x3234; - public override string DeviceModelDescription => "Test Model Description SubDevice"; - public override bool SupportDMXAddress => true; - protected MockGeneratedDeviceWithSubDevice1(UID uid, MockGeneratedDeviceWithSubDeviceSub1[]? subDevices = null, Sensor[]? sensors = null) : base(uid, new ERDM_Parameter[] { ERDM_Parameter.IDENTIFY_DEVICE, ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL }, "Dummy Manufacturer 9FEF", sensors, subDevices) - { - this.DeviceLabel = "Dummy Device Master"; - this.setInitParameters(); - } - protected MockGeneratedDeviceWithSubDevice1(UID uid, SubDevice subDevice, Sensor[]? sensors = null) : base(uid, subDevice, new ERDM_Parameter[] { ERDM_Parameter.IDENTIFY_DEVICE, ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL }, "Dummy Manufacturer 9FEF", sensors) + protected MockGeneratedDeviceWithSubDevice1(UID uid, MockGeneratedDeviceWithSubDeviceSub1[]? subDevices = null, IReadOnlyCollection modules=null) : base(uid, subDevices, modules) { - this.DeviceLabel = "Dummy Device SubDevice"; - this.setInitParameters(); } - private void setInitParameters() + protected MockGeneratedDeviceWithSubDevice1(UID uid, SubDevice subDevice, IReadOnlyCollection modules=null) : base(uid, subDevice, modules) { - this.trySetParameter(ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL, $"Dummy Software"); } - + protected sealed override void OnDispose() { @@ -39,15 +30,27 @@ internal sealed class MockGeneratedDeviceWithSubDeviceMaster1 : MockGeneratedDev private static readonly Sensor[] SENSORS = new Sensor[] { new MockSensorTemp(0, 1, 3000)}; - public override GeneratedPersonality[] Personalities => PERSONALITYS; public override bool SupportQueued => true; - public override bool SupportStatus => true; - - public MockGeneratedDeviceWithSubDeviceMaster1(UID uid, ushort subDevicesCount) : base(uid, getSubDevices(uid, subDevicesCount), SENSORS) + public MockGeneratedDeviceWithSubDeviceMaster1(UID uid, ushort subDevicesCount) : base(uid, getSubDevices(uid, subDevicesCount), GetModulesMaster()) { } + private static IReadOnlyCollection GetModulesMaster() + { + return new IModule[] { + new DeviceLabelModule("Dummy Device Master"), + new ManufacturerLabelModule("Dummy Manufacturer 9FEF"), + new DeviceModelDescriptionModule("Test Model Description Master"), + new SoftwareVersionModule(0x3234, $"Dummy Software"), + new BootSoftwareVersionModule(12359,$"Dummy Software"), + new DMX_StartAddressModule(1), + new DMX_PersonalityModule(1,PERSONALITYS), + new SlotsModule(), + new SensorsModule(SENSORS), + new StatusMessageModule() + }; + } private static MockGeneratedDeviceWithSubDeviceSub1[] getSubDevices(UID uid, ushort count) { @@ -73,14 +76,26 @@ internal sealed class MockGeneratedDeviceWithSubDeviceSub1 : MockGeneratedDevice private static readonly Sensor[] SENSORS = new Sensor[] { new MockSensorTemp(0, 1, 3000)}; - public override GeneratedPersonality[] Personalities => PERSONALITYS; public override bool SupportQueued => true; - public override bool SupportStatus => true; - - public MockGeneratedDeviceWithSubDeviceSub1(UID uid, ushort subDeviceID) : base(uid, getSubDevice(subDeviceID), SENSORS) + public MockGeneratedDeviceWithSubDeviceSub1(UID uid, ushort subDeviceID) : base(uid, getSubDevice(subDeviceID), GetModulesSubDevice()) + { + } + private static IReadOnlyCollection GetModulesSubDevice() { + return new IModule[] { + new DeviceLabelModule("Dummy Device SubDevice"), + new ManufacturerLabelModule("Dummy Manufacturer 9FEF"), + new DeviceModelDescriptionModule("Test Model Description SubDevice"), + new SoftwareVersionModule(0x3234, $"Dummy Software"), + new BootSoftwareVersionModule(12359,$"Dummy Software"), + new DMX_StartAddressModule(1), + new DMX_PersonalityModule(1,PERSONALITYS), + new SlotsModule(), + new SensorsModule(SENSORS), + new StatusMessageModule() + }; } private static SubDevice getSubDevice(ushort subDeviceID) { diff --git a/RDMSharpTests/Devices/Mock/MockGeneratedDevice_SlotOverflow.cs b/RDMSharpTests/Devices/Mock/MockGeneratedDevice_SlotOverflow.cs index e862d7a..ba31254 100644 --- a/RDMSharpTests/Devices/Mock/MockGeneratedDevice_SlotOverflow.cs +++ b/RDMSharpTests/Devices/Mock/MockGeneratedDevice_SlotOverflow.cs @@ -1,4 +1,5 @@ using RDMSharp.Metadata; +using RDMSharp.RDM.Device.Module; namespace RDMSharpTests.Devices.Mock { @@ -14,9 +15,6 @@ public override EManufacturer ManufacturerID public override ushort DeviceModelID => 20; public override ERDM_ProductCategoryCoarse ProductCategoryCoarse => ERDM_ProductCategoryCoarse.CONTROL; public override ERDM_ProductCategoryFine ProductCategoryFine => ERDM_ProductCategoryFine.DATA_CONVERSION; - public override uint SoftwareVersionID => 0x1234; - public override string DeviceModelDescription => "Test Model Description"; - public override bool SupportDMXAddress => true; private static byte[] SLOT_INFO_RAW = new byte[] { 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, @@ -58,11 +56,6 @@ public override EManufacturer ManufacturerID private static readonly GeneratedPersonality[] PERSONALITYS = new GeneratedPersonality[] { PersonalityFromRawData(SLOT_INFO_RAW) }; - private static Sensor[] GetSensors() { - return new Sensor[] {}; - } - public override GeneratedPersonality[] Personalities => PERSONALITYS; - private static GeneratedPersonality PersonalityFromRawData(byte[] bytes) { List slots = new List(); @@ -77,14 +70,22 @@ private static GeneratedPersonality PersonalityFromRawData(byte[] bytes) } public override bool SupportQueued => true; - - public override bool SupportStatus => true; - public MockGeneratedDevice_SlotOverflow(UID uid) : base(uid, SubDevice.Root, new ERDM_Parameter[] { ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL }, "Dummy Manufacturer 9FFF", GetSensors()) + public MockGeneratedDevice_SlotOverflow(UID uid) : base(uid, SubDevice.Root, GetModules()) { - this.DeviceLabel = "Dummy Device 1"; - this.SoftwareVersionLabel = $"Dummy Software"; - this.BootSoftwareVersionLabel = $"Dummy Bootloader Software"; + } + private static IReadOnlyCollection GetModules() + { + return new IModule[] { + new DeviceLabelModule("Dummy Device 1"), + new ManufacturerLabelModule("Dummy Manufacturer 9FFF"), + new DeviceModelDescriptionModule("Test Model Description"), + new SoftwareVersionModule(0x1234, $"Dummy Software"), + new BootSoftwareVersionModule(123, $"Dummy Bootloader Software"), + new DMX_StartAddressModule(1), + new DMX_PersonalityModule(1,PERSONALITYS), + new SlotsModule() + }; } protected sealed override void OnDispose() { diff --git a/RDMSharpTests/Devices/Modules/TestBootSoftwareVersionModule.cs b/RDMSharpTests/Devices/Modules/TestBootSoftwareVersionModule.cs new file mode 100644 index 0000000..2b6d1cc --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestBootSoftwareVersionModule.cs @@ -0,0 +1,101 @@ +using RDMSharp.Metadata; +using RDMSharp.RDM.Device.Module; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules +{ + public class TestBootSoftwareVersionModule + { + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test, Order(30)] + public void TestGetBOOT_SOFTWARE_VERSION_ID() + { + #region Test Basic + Assert.That(generated, Is.Not.Null); + var bootSoftwareVersionModule = generated.Modules.OfType().Single(); + Assert.That(bootSoftwareVersionModule, Is.Not.Null); + Assert.That(bootSoftwareVersionModule.BootSoftwareVersionId, Is.EqualTo(123)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(4)); + Assert.That(response.Value, Is.EqualTo(bootSoftwareVersionModule.BootSoftwareVersionId)); + #endregion + } + [Test, Order(31)] + public void TestGetBOOT_SOFTWARE_VERSION_LABEL() + { + const string BOOT_SOFTWARE_VERSION_LABEL = "Dummy Bootloader Software"; + #region Test Basic + Assert.That(generated, Is.Not.Null); + var bootSoftwareVersionModule = generated.Modules.OfType().Single(); + Assert.That(bootSoftwareVersionModule, Is.Not.Null); + Assert.That(bootSoftwareVersionModule.BootSoftwareVersionLabel, Is.EqualTo(BOOT_SOFTWARE_VERSION_LABEL)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(BOOT_SOFTWARE_VERSION_LABEL.Length)); + Assert.That(response.Value, Is.EqualTo(BOOT_SOFTWARE_VERSION_LABEL)); + #endregion + + #region Test Label changed + bootSoftwareVersionModule.BootSoftwareVersionLabel = "Rem x Ram"; + Assert.That(bootSoftwareVersionModule.BootSoftwareVersionLabel, Is.EqualTo("Rem x Ram")); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(bootSoftwareVersionModule.BootSoftwareVersionLabel.Length)); + Assert.That(response.Value, Is.EqualTo(bootSoftwareVersionModule.BootSoftwareVersionLabel)); + #endregion + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestDMX_PersonalityModule.cs b/RDMSharpTests/Devices/Modules/TestDMX_PersonalityModule.cs new file mode 100644 index 0000000..7ecd323 --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestDMX_PersonalityModule.cs @@ -0,0 +1,119 @@ +using RDMSharp.Metadata; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules; + +public class TestDMX_PersonalityModule +{ + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test, Order(10)] + public void TestGetDMX_PERSONALITY_DESCRIPTION() + { + #region Test Basic + Assert.That(generated, Is.Not.Null); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION, + SubDevice = SubDevice.Root, + ParameterData = new byte[] { 0x00 } // Requesting invalid 0 + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + + for (byte b = 0; b < generated.Personalities.Count; b++) + { + request.ParameterData = new byte[] { (byte)(b + 1) }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + var pers = generated.Personalities.ElementAt(b); + var expected = new RDMDMXPersonalityDescription(pers.ID, pers.SlotCount, pers.Description); + Assert.That(response.ParameterData, Has.Length.EqualTo(expected.ToPayloadData().Length)); + Assert.That(response.Value, Is.EqualTo(expected)); + Assert.That(((RDMDMXPersonalityDescription)response.Value).Index, Is.EqualTo(expected.Index)); + } + #endregion + } + [Test, Order(11)] + public void TestGetDMX_PERSONALITY() + { + #region Test Basic + Assert.That(generated, Is.Not.Null); + Assert.That(generated.CurrentPersonality, Is.EqualTo(1)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.DMX_PERSONALITY, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_PERSONALITY)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + var pers = generated.Personalities.ElementAt(0); + var expected = new RDMDMXPersonality(pers.ID, (byte)generated.Personalities.Count()); + Assert.That(response.ParameterData, Has.Length.EqualTo(expected.ToPayloadData().Length)); + Assert.That(response.Value, Is.EqualTo(expected)); + Assert.That(((RDMDMXPersonality)response.Value).MinIndex, Is.EqualTo(1)); + Assert.That(((RDMDMXPersonality)response.Value).Index, Is.EqualTo(1)); + Assert.That(((RDMDMXPersonality)response.Value).Count, Is.EqualTo(3)); + #endregion + + #region Test Label changed + Assert.That(generated.CurrentPersonality, Is.EqualTo(1)); + generated.CurrentPersonality = 2; + Assert.That(generated.CurrentPersonality, Is.EqualTo(2)); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_PERSONALITY)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + pers = generated.Personalities.ElementAt(1); + expected = new RDMDMXPersonality(pers.ID, (byte)generated.Personalities.Count()); + Assert.That(response.ParameterData, Has.Length.EqualTo(expected.ToPayloadData().Length)); + Assert.That(response.Value, Is.EqualTo(expected)); + #endregion + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestDMX_StartAddressModule.cs b/RDMSharpTests/Devices/Modules/TestDMX_StartAddressModule.cs new file mode 100644 index 0000000..f457cec --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestDMX_StartAddressModule.cs @@ -0,0 +1,69 @@ +using RDMSharp.Metadata; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules +{ + public class TestDMX_StartAddressModule + { + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test, Order(7)] + public void TestGetDMX_START_ADDRESS() + { + #region Test Basic + Assert.That(generated, Is.Not.Null); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.DMX_START_ADDRESS, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_START_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(2)); + Assert.That(response.Value, Is.EqualTo(generated.DMXAddress)); + #endregion + + + #region Test Address changed + generated.DMXAddress = 40; + Assert.That(generated.DMXAddress, Is.EqualTo(40)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_START_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(2)); + Assert.That(response.Value, Is.EqualTo(generated.DMXAddress)); + #endregion + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestDeviceInfoModule.cs b/RDMSharpTests/Devices/Modules/TestDeviceInfoModule.cs new file mode 100644 index 0000000..af80962 --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestDeviceInfoModule.cs @@ -0,0 +1,55 @@ +using RDMSharp.Metadata; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules +{ + public class TestDeviceInfoModule + { + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test, Order(5)] + public void TestGetDEVICE_INFO() + { + #region Test Basic + Assert.That(generated, Is.Not.Null); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.DEVICE_INFO, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_INFO)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(19)); + Assert.That(response.Value, Is.EqualTo(generated.DeviceInfo)); + RDMDeviceInfo? deviceInfo = response!.Value as RDMDeviceInfo; + Assert.That(deviceInfo, Is.Not.Null); + Assert.That(deviceInfo.SensorCount, Is.EqualTo(5)); + #endregion + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestDeviceLabelModule.cs b/RDMSharpTests/Devices/Modules/TestDeviceLabelModule.cs new file mode 100644 index 0000000..a6c5adb --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestDeviceLabelModule.cs @@ -0,0 +1,72 @@ +using RDMSharp.Metadata; +using RDMSharp.RDM.Device.Module; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules +{ + public class TestDeviceLabelModule + { + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test, Order(9)] + public void TestGetDEVICE_LABEL() + { + #region Test Basic + Assert.That(generated, Is.Not.Null); + var deviceLabelModule = generated.Modules.OfType().Single(); + Assert.That(deviceLabelModule, Is.Not.Null); + Assert.That(deviceLabelModule.DeviceLabel, Is.EqualTo("Dummy Device 1")); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.DEVICE_LABEL, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_LABEL)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(deviceLabelModule.DeviceLabel.Length)); + Assert.That(response.Value, Is.EqualTo(deviceLabelModule.DeviceLabel)); + #endregion + + #region Test Label changed + Assert.That(deviceLabelModule.DeviceLabel, Is.EqualTo("Dummy Device 1")); + deviceLabelModule.DeviceLabel = "Rem x Ram"; + Assert.That(deviceLabelModule.DeviceLabel, Is.EqualTo("Rem x Ram")); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_LABEL)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(deviceLabelModule.DeviceLabel.Length)); + Assert.That(response.Value, Is.EqualTo(deviceLabelModule.DeviceLabel)); + #endregion + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestDeviceModelDescriptionModule.cs b/RDMSharpTests/Devices/Modules/TestDeviceModelDescriptionModule.cs new file mode 100644 index 0000000..e768736 --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestDeviceModelDescriptionModule.cs @@ -0,0 +1,56 @@ +using RDMSharp.Metadata; +using RDMSharp.RDM.Device.Module; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules +{ + public class TestDeviceModelDescriptionModule + { + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test, Order(16)] + public void TestGetDEVICE_MODEL_DESCRIPTION() + { + #region Test Basic + Assert.That(generated, Is.Not.Null); + var deviceModelDescriptionModule = generated.Modules.OfType().Single(); + Assert.That(deviceModelDescriptionModule, Is.Not.Null); + Assert.That(deviceModelDescriptionModule.DeviceModelDescription, Is.EqualTo("Test Model Description")); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.DEVICE_MODEL_DESCRIPTION, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_MODEL_DESCRIPTION)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(deviceModelDescriptionModule.DeviceModelDescription.Length)); + Assert.That(response.Value, Is.EqualTo(deviceModelDescriptionModule.DeviceModelDescription)); + #endregion + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestIdentifyDeviceModule.cs b/RDMSharpTests/Devices/Modules/TestIdentifyDeviceModule.cs new file mode 100644 index 0000000..33c5d8e --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestIdentifyDeviceModule.cs @@ -0,0 +1,124 @@ +using RDMSharp.Metadata; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules +{ + public class TestIdentifyDeviceModule + { + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + [Test, Order(6)] + public void TestGetIDENTIFY_DEVICE() + { + #region Test Basic + Assert.That(generated, Is.Not.Null); + Assert.That(generated.Identify, Is.False); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.IDENTIFY_DEVICE, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(1)); + Assert.That(response.Value, Is.EqualTo(generated.Identify)); + #endregion + + #region Test Identify changed (GET) + Assert.That(generated.Identify, Is.False); + generated.Identify = true; + Assert.That(generated.Identify, Is.True); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(1)); + Assert.That(response.Value, Is.EqualTo(generated.Identify)); + #endregion + + + #region Test Identify changed (SET) + Assert.That(generated.Identify, Is.True); + request.ParameterData = new byte[] { 0x00 }; // Requesting Identify OFF + request.Command = ERDM_Command.SET_COMMAND; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + + Assert.That(generated.Identify, Is.False); + request.Command = ERDM_Command.GET_COMMAND; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(1)); + Assert.That(response.Value, Is.EqualTo(generated.Identify)); + + request.ParameterData = new byte[] { 0x01 }; // Requesting Identify OFF + request.Command = ERDM_Command.SET_COMMAND; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + + Assert.That(generated.Identify, Is.True); + + request.Command = ERDM_Command.GET_COMMAND; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(1)); + Assert.That(response.Value, Is.EqualTo(generated.Identify)); + + #endregion + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestInterfaceModlue.cs b/RDMSharpTests/Devices/Modules/TestInterfaceModlue.cs new file mode 100644 index 0000000..627d967 --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestInterfaceModlue.cs @@ -0,0 +1,1050 @@ +using RDMSharp.Metadata; +using RDMSharp.RDM.Device.Module; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules; + +public class TestInterfaceModlue +{ + private InterfaceMockDevice? generated; + private InterfaceModule? interfaceModule; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + private const string TEST_INTERFACE_NAME = "Test Interface"; + private const string TEST_INTERFACE_HARDWARE_ADDRESS = "e0:63:da:5a:c4:fb"; + private const EARP_HardwareTypes TEST_INTERFACE_HARDWARE_TYPE = EARP_HardwareTypes.Ethernet; + private const string TEST_INTERFACE_IP_ADDRESS = "2.3.4.5"; + private static RDMMessage APPLY_CONFIG_MESSAGE = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION, + SubDevice = SubDevice.Root, + ParameterData = Tools.ValueToData((uint)1) + }; + + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new InterfaceMockDevice(DEVCIE_UID); + interfaceModule = generated.Modules.OfType().FirstOrDefault(); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + interfaceModule = null; + } + + [Test, Order(1)] + public void TestGetLIST_INTERFACES() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + Assert.That(interfaceModule, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Has.Count.Not.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.LIST_INTERFACES, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.LIST_INTERFACES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(6)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(InterfaceDescriptor[]))); + var interfaces = (InterfaceDescriptor[])response.Value; + Assert.That(interfaces, Has.Length.EqualTo(1)); + Assert.That(interfaces[0].InterfaceId, Is.EqualTo(1)); + Assert.That(interfaces[0].HardwareType, Is.EqualTo(EARP_HardwareTypes.Ethernet)); + + #endregion + + } + [Test, Order(2)] + public void TestGetINTERFACE_LABEL() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + Assert.That(interfaceModule, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Has.Count.Not.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.INTERFACE_LABEL, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_LABEL)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + Assert.That(response.Value, Is.Null); + + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_LABEL)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(18)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetInterfaceNameResponse))); + var interfaceNameResponse = (GetInterfaceNameResponse)response.Value; + Assert.That(interfaceNameResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceNameResponse.Label, Is.EqualTo(TEST_INTERFACE_NAME)); + #endregion + + request.ParameterData = Tools.ValueToData((uint)2); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_LABEL)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + Assert.That(response.Value, Is.Null); + } + [Test, Order(3)] + public void TestGetINTERFACE_HARDWARE_ADDRESS_TYPE() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + Assert.That(interfaceModule, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Has.Count.Not.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.INTERFACE_HARDWARE_ADDRESS_TYPE, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_HARDWARE_ADDRESS_TYPE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + Assert.That(response.Value, Is.Null); + + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_HARDWARE_ADDRESS_TYPE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(10)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetHardwareAddressResponse))); + var interfaceHardwareAddressResponse = (GetHardwareAddressResponse)response.Value; + Assert.That(interfaceHardwareAddressResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceHardwareAddressResponse.HardwareAddress, Is.EqualTo(new MACAddress(TEST_INTERFACE_HARDWARE_ADDRESS))); + #endregion + + request.ParameterData = Tools.ValueToData((uint)2); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_HARDWARE_ADDRESS_TYPE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + Assert.That(response.Value, Is.Null); + } + [Test, Order(4)] + public void TestGetIPV4_CURRENT_ADDRESS() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + Assert.That(interfaceModule, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Has.Count.Not.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.IPV4_CURRENT_ADDRESS, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_CURRENT_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + Assert.That(response.Value, Is.Null); + + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_CURRENT_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(10)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetIPv4CurrentAddressResponse))); + var interfaceIPv4CurrentAddressResponse = (GetIPv4CurrentAddressResponse)response.Value; + Assert.That(interfaceIPv4CurrentAddressResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceIPv4CurrentAddressResponse.IPAddress, Is.EqualTo(new IPv4Address(TEST_INTERFACE_IP_ADDRESS))); + Assert.That(interfaceIPv4CurrentAddressResponse.Netmask, Is.EqualTo(8)); + Assert.That(interfaceIPv4CurrentAddressResponse.DHCPStatus, Is.EqualTo(ERDM_DHCPStatusMode.INACTIVE)); + #endregion + + request.ParameterData = Tools.ValueToData((uint)2); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_CURRENT_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + Assert.That(response.Value, Is.Null); + } + + [Test, Order(5)] + public void TestGetIPV4_DHCP_MODE() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + Assert.That(interfaceModule, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Has.Count.Not.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.IPV4_DHCP_MODE, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_DHCP_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + Assert.That(response.Value, Is.Null); + + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_DHCP_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(5)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetSetIPV4_xxx_Mode))); + var interfaceResponse = (GetSetIPV4_xxx_Mode)response.Value; + Assert.That(interfaceResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceResponse.Enabled, Is.False); + + interfaceModule.Interfaces.First().DHCP = true; + interfaceModule.Interfaces.First().DHCP = true; //For Coverage + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_DHCP_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(5)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetSetIPV4_xxx_Mode))); + interfaceResponse = (GetSetIPV4_xxx_Mode)response.Value; + Assert.That(interfaceResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceResponse.Enabled, Is.True); + #endregion + + request.ParameterData = Tools.ValueToData((uint)2); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_DHCP_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + Assert.That(response.Value, Is.Null); + } + [Test, Order(6)] + public void TestSetIPV4_DHCP_MODE() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + Assert.That(interfaceModule, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Has.Count.Not.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.IPV4_DHCP_MODE, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_DHCP_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + Assert.That(response.Value, Is.Null); + + request.ParameterData = Tools.ValueToData(new GetSetIPV4_xxx_Mode(1, true)); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_DHCP_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + + request.Command = ERDM_Command.GET_COMMAND; + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_DHCP_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(5)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetSetIPV4_xxx_Mode))); + var interfaceResponse = (GetSetIPV4_xxx_Mode)response.Value; + Assert.That(interfaceResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceResponse.Enabled, Is.False); + + response = generated.ProcessRequestMessage_Internal(APPLY_CONFIG_MESSAGE); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_DHCP_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(5)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetSetIPV4_xxx_Mode))); + interfaceResponse = (GetSetIPV4_xxx_Mode)response.Value; + Assert.That(interfaceResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceResponse.Enabled, Is.True); + #endregion + + request.Command = ERDM_Command.SET_COMMAND; + request.ParameterData = Tools.ValueToData(new GetSetIPV4_xxx_Mode(2, true)); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_DHCP_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + Assert.That(response.Value, Is.Null); + } + + [Test, Order(7)] + public void TestGetIPV4_ZEROCONF_MODE() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + Assert.That(interfaceModule, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Has.Count.Not.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.IPV4_ZEROCONF_MODE, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_ZEROCONF_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + Assert.That(response.Value, Is.Null); + + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_ZEROCONF_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(5)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetSetIPV4_xxx_Mode))); + var interfaceResponse = (GetSetIPV4_xxx_Mode)response.Value; + Assert.That(interfaceResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceResponse.Enabled, Is.True); + + + interfaceModule.Interfaces.First().ZeroConf = false; + interfaceModule.Interfaces.First().ZeroConf = false; //For Coverage + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_ZEROCONF_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(5)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetSetIPV4_xxx_Mode))); + interfaceResponse = (GetSetIPV4_xxx_Mode)response.Value; + Assert.That(interfaceResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceResponse.Enabled, Is.False); + #endregion + + request.ParameterData = Tools.ValueToData((uint)2); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_ZEROCONF_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + Assert.That(response.Value, Is.Null); + } + + [Test, Order(8)] + public void TestSetIPV4_ZEROCONF_MODE() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + Assert.That(interfaceModule, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Has.Count.Not.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.IPV4_ZEROCONF_MODE, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_ZEROCONF_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + Assert.That(response.Value, Is.Null); + + request.ParameterData = Tools.ValueToData(new GetSetIPV4_xxx_Mode(1, false)); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_ZEROCONF_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + + request.Command = ERDM_Command.GET_COMMAND; + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_ZEROCONF_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(5)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetSetIPV4_xxx_Mode))); + var interfaceResponse = (GetSetIPV4_xxx_Mode)response.Value; + Assert.That(interfaceResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceResponse.Enabled, Is.True); + + + response = generated.ProcessRequestMessage_Internal(APPLY_CONFIG_MESSAGE); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_ZEROCONF_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(5)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetSetIPV4_xxx_Mode))); + interfaceResponse = (GetSetIPV4_xxx_Mode)response.Value; + Assert.That(interfaceResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceResponse.Enabled, Is.False); + + #endregion + + request.Command = ERDM_Command.SET_COMMAND; + request.ParameterData = Tools.ValueToData(new GetSetIPV4_xxx_Mode(2, true)); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_ZEROCONF_MODE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + Assert.That(response.Value, Is.Null); + } + + [Test, Order(9)] + public void TestGetIPV4_STATIC_ADDRESS() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + Assert.That(interfaceModule, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Has.Count.Not.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.IPV4_STATIC_ADDRESS, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_STATIC_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + Assert.That(response.Value, Is.Null); + + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_STATIC_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(9)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetSetIPv4StaticAddress))); + var interfaceIPv4StaticAddressResponse = (GetSetIPv4StaticAddress)response.Value; + Assert.That(interfaceIPv4StaticAddressResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceIPv4StaticAddressResponse.IPAddress, Is.EqualTo(new IPv4Address(TEST_INTERFACE_IP_ADDRESS))); + Assert.That(interfaceIPv4StaticAddressResponse.Netmask, Is.EqualTo(8)); + + IPv4Address oneDotOneDotOneDotOne = new IPv4Address("1.1.1.1"); + var iface = interfaceModule.Interfaces.First(); + iface.SetStaticIP(oneDotOneDotOneDotOne, 24); + Assert.That(iface.CurrentIP, Is.EqualTo(oneDotOneDotOneDotOne)); + Assert.That(iface.CurrentSubnetMask, Is.EqualTo(24)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_STATIC_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(9)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetSetIPv4StaticAddress))); + interfaceIPv4StaticAddressResponse = (GetSetIPv4StaticAddress)response.Value; + Assert.That(interfaceIPv4StaticAddressResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceIPv4StaticAddressResponse.IPAddress, Is.EqualTo(oneDotOneDotOneDotOne)); + Assert.That(interfaceIPv4StaticAddressResponse.Netmask, Is.EqualTo(24)); + #endregion + + request.ParameterData = Tools.ValueToData((uint)2); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_STATIC_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + Assert.That(response.Value, Is.Null); + } + [Test, Order(10)] + public void TestSetIPV4_STATIC_ADDRESS() + { + IPv4Address oneDotOneDotOneDotOne = new IPv4Address("1.1.1.1"); + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + Assert.That(interfaceModule, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Has.Count.Not.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.IPV4_STATIC_ADDRESS, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_STATIC_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + Assert.That(response.Value, Is.Null); + + request.ParameterData = Tools.ValueToData(new GetSetIPv4StaticAddress(1, oneDotOneDotOneDotOne, 24)); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_STATIC_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + + request.Command = ERDM_Command.GET_COMMAND; + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_STATIC_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(9)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetSetIPv4StaticAddress))); + var interfaceResponse = (GetSetIPv4StaticAddress)response.Value; + Assert.That(interfaceResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceResponse.IPAddress, Is.EqualTo(new IPv4Address(TEST_INTERFACE_IP_ADDRESS))); + Assert.That(interfaceResponse.Netmask, Is.EqualTo(8)); + + + response = generated.ProcessRequestMessage_Internal(APPLY_CONFIG_MESSAGE); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_STATIC_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(9)); + Assert.That(response.Value, Is.Not.Null); + Assert.That(response.Value, Is.TypeOf(typeof(GetSetIPv4StaticAddress))); + interfaceResponse = (GetSetIPv4StaticAddress)response.Value; + Assert.That(interfaceResponse.InterfaceId, Is.EqualTo(1)); + Assert.That(interfaceResponse.IPAddress, Is.EqualTo(oneDotOneDotOneDotOne)); + Assert.That(interfaceResponse.Netmask, Is.EqualTo(24)); + + #endregion + + request.Command = ERDM_Command.SET_COMMAND; + request.ParameterData = Tools.ValueToData(new GetSetIPv4StaticAddress(2, oneDotOneDotOneDotOne, 31)); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IPV4_STATIC_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + Assert.That(response.Value, Is.Null); + } + + [Test, Order(11)] + public void TestSetINTERFACE_APPLY_CONFIGURATION() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + Assert.That(interfaceModule, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Has.Count.Not.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + Assert.That(response.Value, Is.Null); + + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + Assert.That(response.Value, Is.Null); + + #endregion + + request.ParameterData = Tools.ValueToData((uint)2); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_APPLY_CONFIGURATION)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + Assert.That(response.Value, Is.Null); + } + + [Test, Order(11)] + public void TestSetINTERFACE_RENEW_DHCP() + { + var iface = interfaceModule.Interfaces.First(); + iface.DHCP = true; + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + Assert.That(interfaceModule, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Has.Count.Not.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.INTERFACE_RENEW_DHCP, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_RENEW_DHCP)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + Assert.That(response.Value, Is.Null); + + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_RENEW_DHCP)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.ACTION_NOT_SUPPORTED)); + Assert.That(response.Value, Is.Null); + + iface.SetStaticIP(IPv4Address.Empty, 0); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_RENEW_DHCP)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + Assert.That(response.Value, Is.Null); + + Assert.That(iface.CurrentIP, Is.EqualTo(InterfaceMock.DHCP_ADDRESS_1)); + + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_RENEW_DHCP)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + Assert.That(response.Value, Is.Null); + + Assert.That(iface.CurrentIP, Is.EqualTo(InterfaceMock.DHCP_ADDRESS_2)); + + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_RENEW_DHCP)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + Assert.That(response.Value, Is.Null); + + Assert.That(iface.CurrentIP, Is.EqualTo(InterfaceMock.DHCP_ADDRESS_3)); + + #endregion + + request.ParameterData = Tools.ValueToData((uint)2); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_RENEW_DHCP)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + Assert.That(response.Value, Is.Null); + } + [Test, Order(12)] + public void TestSetINTERFACE_RELEASE_DHCP() + { + var iface = interfaceModule.Interfaces.First(); + iface.DHCP = true; + iface.SetStaticIP(IPv4Address.Empty, 0); + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + Assert.That(interfaceModule, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Is.Not.Null); + Assert.That(interfaceModule.Interfaces, Has.Count.Not.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.INTERFACE_RENEW_DHCP, + SubDevice = SubDevice.Root, + ParameterData = Tools.ValueToData((uint)1) + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(iface.CurrentIP, Is.EqualTo(InterfaceMock.DHCP_ADDRESS_1)); + + request.Parameter = ERDM_Parameter.INTERFACE_RELEASE_DHCP; + request.ParameterData = null; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_RELEASE_DHCP)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + Assert.That(response.Value, Is.Null); + + request.ParameterData = Tools.ValueToData((uint)1); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_RELEASE_DHCP)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + Assert.That(response.Value, Is.Null); + + Assert.That(iface.CurrentIP, Is.EqualTo(IPv4Address.Empty)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_RELEASE_DHCP)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.ACTION_NOT_SUPPORTED)); + Assert.That(response.Value, Is.Null); + #endregion + + request.ParameterData = Tools.ValueToData((uint)2); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.INTERFACE_RELEASE_DHCP)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + Assert.That(response.Value, Is.Null); + } + + class InterfaceMockDevice : MockGeneratedDevice1 + { + public InterfaceMockDevice(UID uid) : base(uid, new IModule[] { new InterfaceModule(new Interface[] { new InterfaceMock() }) }) + { + } + } + class InterfaceMock : Interface + { + public static IPv4Address DHCP_ADDRESS_1 = new IPv4Address("2.5.5.5"); + public static IPv4Address DHCP_ADDRESS_2 = new IPv4Address("2.6.6.6"); + public static IPv4Address DHCP_ADDRESS_3 = new IPv4Address("2.7.7.7"); + public InterfaceMock() + : base(1, + TEST_INTERFACE_NAME, + new IPv4Address(TEST_INTERFACE_IP_ADDRESS), + 8, + new MACAddress(TEST_INTERFACE_HARDWARE_ADDRESS), + TEST_INTERFACE_HARDWARE_TYPE) + { + } + public override void RenewDHCP() + { + switch (this.CurrentIP.B2) + { + default: + case 0: + this.SetCurrentIP(DHCP_ADDRESS_1, 8, true); + break; + case 5: + this.SetCurrentIP(DHCP_ADDRESS_2, 8, true); + break; + case 6: + this.SetCurrentIP(DHCP_ADDRESS_3, 8, true); + break; + } + } + public override void ReleaseDHCP() + { + this.SetCurrentIP(IPv4Address.Empty, 8, false); + base.ReleaseDHCP(); + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestManufacturerLabelModule.cs b/RDMSharpTests/Devices/Modules/TestManufacturerLabelModule.cs new file mode 100644 index 0000000..fd27b39 --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestManufacturerLabelModule.cs @@ -0,0 +1,56 @@ +using RDMSharp.Metadata; +using RDMSharp.RDM.Device.Module; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules +{ + public class TestManufacturerLabelModule + { + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test, Order(15)] + public void TestGetMANUFACTURER_LABEL() + { + #region Test Basic + Assert.That(generated, Is.Not.Null); + var manufacturerLabelModule = generated.Modules.OfType().Single(); + Assert.That(manufacturerLabelModule, Is.Not.Null); + Assert.That(manufacturerLabelModule.ManufacturerLabel, Is.EqualTo("Dummy Manufacturer 9FFF")); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.MANUFACTURER_LABEL, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.MANUFACTURER_LABEL)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(manufacturerLabelModule.ManufacturerLabel.Length)); + Assert.That(response.Value, Is.EqualTo(manufacturerLabelModule.ManufacturerLabel)); + #endregion + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestProxiedDevicesModlue.cs b/RDMSharpTests/Devices/Modules/TestProxiedDevicesModlue.cs new file mode 100644 index 0000000..6360ffd --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestProxiedDevicesModlue.cs @@ -0,0 +1,234 @@ +using RDMSharp.Metadata; +using RDMSharp.RDM.Device.Module; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules; + +public class TestProxiedDevicesModlue +{ + private ProxiedDevicesMockDevice? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 3453); + private static UID DEVCIE_UID = new UID(123, 5225); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new ProxiedDevicesMockDevice(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + + [Test, Retry(3), Order(1)] + public void TestGetPROXIED_DEVICES_COUNT() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + var proxiedDevicesModule = generated.Modules.OfType().FirstOrDefault(); + Assert.That(proxiedDevicesModule, Is.Not.Null); + Assert.That(proxiedDevicesModule.DeviceUIDs, Is.Not.Null); + Assert.That(proxiedDevicesModule.DeviceUIDs, Has.Count.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.PROXIED_DEVICES_COUNT, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.PROXIED_DEVICES_COUNT)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(3)); + Assert.That(response.Value, Is.EqualTo(new RDMProxiedDeviceCount(0, false))); + #endregion + + proxiedDevicesModule.AddProxiedDevices(new UID(12, 3456), new UID(12, 2345)); + + for (int i = 0; i < 5; i++) + { + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.PROXIED_DEVICES_COUNT)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(3)); + Assert.That(response.Value, Is.EqualTo(new RDMProxiedDeviceCount(2, true))); + } + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.PROXIED_DEVICES, + SubDevice = SubDevice.Root, + }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.PROXIED_DEVICES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(12)); + Assert.That(response.Value, Is.EqualTo(new RDMProxiedDevices(new UID(12, 3456), new UID(12, 2345)))); + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.PROXIED_DEVICES_COUNT, + SubDevice = SubDevice.Root, + }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.PROXIED_DEVICES_COUNT)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(3)); + Assert.That(response.Value, Is.EqualTo(new RDMProxiedDeviceCount(2, false))); + + + proxiedDevicesModule.RemoveProxiedDevices(new UID(12, 3456)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.PROXIED_DEVICES_COUNT)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(3)); + Assert.That(response.Value, Is.EqualTo(new RDMProxiedDeviceCount(1, true))); + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.PROXIED_DEVICES, + SubDevice = SubDevice.Root, + }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.PROXIED_DEVICES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(6)); + Assert.That(response.Value, Is.EqualTo(new RDMProxiedDevices(new UID(12, 2345)))); + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.PROXIED_DEVICES_COUNT, + SubDevice = SubDevice.Root, + }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.PROXIED_DEVICES_COUNT)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(3)); + Assert.That(response.Value, Is.EqualTo(new RDMProxiedDeviceCount(1, false))); + + List uidsToAdd = new List(); + uidsToAdd.Add(new UID(12, 2345)); + for (int i = 0; i < 134; i++) + uidsToAdd.Add(new UID(12, (ushort)(3456 + i))); + + proxiedDevicesModule.AddProxiedDevices(uidsToAdd.ToArray()); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.PROXIED_DEVICES_COUNT)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(3)); + Assert.That(response.Value, Is.EqualTo(new RDMProxiedDeviceCount(135, true))); + + var chunks = uidsToAdd.Chunk(38); + int totalResponses = 0; + for (int i = 0; i < chunks.Count(); i++) + { + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.PROXIED_DEVICES, + SubDevice = SubDevice.Root, + }; + response = generated.ProcessRequestMessage_Internal(request); + totalResponses++; + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.PROXIED_DEVICES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.MessageCounter, Is.EqualTo(chunks.Count() - totalResponses)); + Assert.That(response.ParameterData, Has.Length.EqualTo(chunks.ElementAt(i).Count() * 6)); + Assert.That(response.Value, Is.EqualTo(new RDMProxiedDevices(chunks.ElementAt(i).ToArray()))); + } + Assert.That(totalResponses, Is.EqualTo(chunks.Count())); + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.PROXIED_DEVICES_COUNT, + SubDevice = SubDevice.Root, + }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.PROXIED_DEVICES_COUNT)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(3)); + Assert.That(response.Value, Is.EqualTo(new RDMProxiedDeviceCount(135, false))); + } + + class ProxiedDevicesMockDevice : MockGeneratedDevice1 + { + public ProxiedDevicesMockDevice(UID uid) : base(uid, new IModule[] { new ProxiedDevicesModule() }) + { + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestQueuedMessageModule.cs b/RDMSharpTests/Devices/Modules/TestQueuedMessageModule.cs new file mode 100644 index 0000000..5d9c110 --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestQueuedMessageModule.cs @@ -0,0 +1,307 @@ +using RDMSharp.Metadata; +using RDMSharp.RDM.Device.Module; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules; + +public class TestQueuedMessageModule +{ + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test] + public void TestGetQUEUED_MESSAGE() + { + #region Test Empty queue + Assert.That(generated, Is.Not.Null); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.QUEUED_MESSAGE, + SubDevice = SubDevice.Root, + ParameterData = new byte[] { (byte)ERDM_Status.ADVISORY } + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + #endregion + + #region Test set DMX-Address (single value changed) + Assert.That(generated.DMXAddress, Is.EqualTo(1)); + generated.DMXAddress = 42; + Assert.That(generated.DMXAddress, Is.EqualTo(42)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_START_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(1)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(2)); + Assert.That(response.Value, Is.EqualTo(generated.DMXAddress)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_INFO)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(0)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(19)); + Assert.That(response.Value, Is.EqualTo(generated.DeviceInfo)); + #endregion + + #region Test Get last Message + request.ParameterData = new byte[] { (byte)ERDM_Status.GET_LAST_MESSAGE }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_INFO)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(0)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(19)); + Assert.That(response.Value, Is.EqualTo(generated.DeviceInfo)); + #endregion + + #region Test set DMX-Address (multiple value changed) + Assert.That(generated.DMXAddress, Is.EqualTo(42)); + generated.DMXAddress = 50; + Assert.That(generated.DMXAddress, Is.EqualTo(50)); + generated.DMXAddress = 60; + Assert.That(generated.DMXAddress, Is.EqualTo(60)); + generated.DMXAddress = 70; + Assert.That(generated.DMXAddress, Is.EqualTo(70)); + generated.DMXAddress = 80; + Assert.That(generated.DMXAddress, Is.EqualTo(80)); + + request.ParameterData = new byte[] { (byte)ERDM_Status.ERROR }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_START_ADDRESS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(1)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(2)); + Assert.That(response.Value, Is.EqualTo(generated.DMXAddress)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_INFO)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(0)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(19)); + Assert.That(response.Value, Is.EqualTo(generated.DeviceInfo)); + #endregion + + #region Test set DeviceLabel (single value changed) + var deviceLabelModule = generated.Modules.OfType().FirstOrDefault(); + Assert.That(deviceLabelModule, Is.Not.Null); + Assert.That(deviceLabelModule.DeviceLabel, Is.EqualTo("Dummy Device 1")); + deviceLabelModule.DeviceLabel = "Test Device Queued Message 1"; + Assert.That(deviceLabelModule.DeviceLabel, Is.EqualTo("Test Device Queued Message 1")); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_LABEL)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(0)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(deviceLabelModule.DeviceLabel.Length)); + Assert.That(response.Value, Is.EqualTo(deviceLabelModule.DeviceLabel)); + #endregion + + #region Test set Multiple Parameter at once + deviceLabelModule.DeviceLabel = "GG"; + Assert.That(deviceLabelModule.DeviceLabel, Is.EqualTo("GG")); + generated.SetParameter(ERDM_Parameter.IDENTIFY_DEVICE, true); + generated.CurrentPersonality = 2; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_LABEL)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(13)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(deviceLabelModule.DeviceLabel.Length)); + Assert.That(response.Value, Is.EqualTo(deviceLabelModule.DeviceLabel)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(12)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(1)); + Assert.That(response.Value, Is.EqualTo(true)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_PERSONALITY)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(11)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(2)); + Assert.That(response.Value, Is.EqualTo(new RDMDMXPersonality(2, 3))); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_INFO)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(10)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(40)); + Assert.That(response.Value, Is.EqualTo(generated.Personalities.ElementAt(1).Slots.Select(s => new RDMSlotInfo(s.Value.SlotId, s.Value.Type, s.Value.Category)))); + + for (byte b = 0; b < generated.Personalities.ElementAt(1).SlotCount; b++) + { + var slot = generated.Personalities.ElementAt(1).Slots[b]; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_DESCRIPTION)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(9 - b)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(generated.Personalities.ElementAt(1).Slots[b].Description.Length + 2)); + Assert.That(response.Value, Is.EqualTo(new RDMSlotDescription(slot.SlotId, slot.Description))); + } + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEFAULT_SLOT_VALUE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(1)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(3 * generated.Personalities.ElementAt(1).Slots.Count)); + Assert.That(response.Value, Is.EqualTo(generated.Personalities.ElementAt(1).Slots.Select(s => new RDMDefaultSlotValue(s.Value.SlotId, s.Value.DefaultValue)))); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_INFO)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(0)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(19)); + Assert.That(response.Value, Is.EqualTo(generated.DeviceInfo)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(0)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + #endregion + + request.ParameterData = new byte[] { (byte)ERDM_Status.ADVISORY }; + var sm = new RDMStatusMessage(0, ERDM_Status.ADVISORY, ERDM_StatusMessage.AMPS, 222); + generated.AddStatusMessage(sm); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(0)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(9)); + Assert.That(response.Value, Is.TypeOf(typeof(RDMStatusMessage[]))); + RDMStatusMessage[] messages = (RDMStatusMessage[])response.Value; + Assert.That(messages[0], Is.EqualTo(sm)); + + #region + request.ParameterData = new byte[] { (byte)ERDM_Status.NONE }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.QUEUED_MESSAGE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(0)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + #endregion + + #region CLEAR_STATUS_ID + request.ParameterData = new byte[] { }; + request.Parameter = ERDM_Parameter.CLEAR_STATUS_ID; + request.Command = ERDM_Command.SET_COMMAND; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CLEAR_STATUS_ID)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(0)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + #endregion + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestRealTimeClockModule.cs b/RDMSharpTests/Devices/Modules/TestRealTimeClockModule.cs new file mode 100644 index 0000000..328a331 --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestRealTimeClockModule.cs @@ -0,0 +1,73 @@ +using RDMSharp.Metadata; +using RDMSharp.RDM.Device.Module; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules +{ + public class TestRealTimeClockModule + { + private RealTimeClockModuleMockDevice? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new RealTimeClockModuleMockDevice(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test, Retry(3), Order(1)] + public async Task TestGetREAL_TIME_CLOCK() + { + await Task.Delay(500); + #region Test Basic + Assert.That(generated, Is.Not.Null); + await Task.Delay(1000); + var realTimeClockModule = generated.Modules.OfType().FirstOrDefault(); + Assert.That(realTimeClockModule, Is.Not.Null); + Assert.That(realTimeClockModule.RealTimeClock, Is.Not.Null); + Assert.That(realTimeClockModule.RealTimeClock.Value.Minute, Is.EqualTo(DateTime.Now.Minute)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.REAL_TIME_CLOCK, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.REAL_TIME_CLOCK)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(7)); + Assert.That(response.Value, Is.TypeOf(typeof(RDMRealTimeClock))); + var timeGen = new RDMRealTimeClock(realTimeClockModule.RealTimeClock.Value); + var timeRem = (RDMRealTimeClock)response.Value; + Assert.That(timeRem.Year, Is.EqualTo(timeGen.Year)); + Assert.That(timeRem.Month, Is.EqualTo(timeGen.Month)); + Assert.That(timeRem.Day, Is.EqualTo(timeGen.Day)); + Assert.That(timeRem.Minute, Is.EqualTo(timeGen.Minute)); + Assert.That(timeRem.Second, Is.AtLeast(timeGen.Second - 2).And.AtMost(timeGen.Second + 2)); + #endregion + + } + class RealTimeClockModuleMockDevice : MockGeneratedDevice1 + { + public RealTimeClockModuleMockDevice(UID uid) : base(uid, new IModule[] { new RealTimeClockModule() }) + { + } + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestSensorsModule.cs b/RDMSharpTests/Devices/Modules/TestSensorsModule.cs new file mode 100644 index 0000000..6e5bee7 --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestSensorsModule.cs @@ -0,0 +1,325 @@ +using RDMSharp.Metadata; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules; + +public class TestSensorsModule +{ + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test, Order(51)] + public void TestGetSENSOR_DEFINITION() + { + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.SENSOR_DEFINITION, + SubDevice = SubDevice.Root, + }; + RDMMessage? response = null; + #region Test Basic + Assert.That(generated, Is.Not.Null); + Assert.That(generated.Sensors, Has.Count.EqualTo(5)); + doTests(generated.Sensors.Values.ToArray()); + #endregion + + void doTests(Sensor[] sensors) + { + foreach (Sensor sensor in sensors) + { + request.ParameterData = new byte[] { sensor.SensorId }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SENSOR_DEFINITION)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(13 + sensor.Description.Length)); + Assert.That(response.Value, Is.EqualTo(new RDMSensorDefinition(sensor.SensorId, sensor.Type, sensor.Unit, sensor.Prefix, sensor.RangeMinimum, sensor.RangeMaximum, sensor.NormalMinimum, sensor.NormalMaximum, sensor.LowestHighestValueSupported, sensor.RecordedValueSupported, sensor.Description))); + } + } + } + + [Test, Order(52)] + public void TestGetSENSOR_VALUE() + { + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.SENSOR_VALUE, + SubDevice = SubDevice.Root, + }; + RDMMessage? response = null; + #region Test Basic + Assert.That(generated, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(generated.Sensors, Has.Count.EqualTo(5)); + + Assert.That(generated.Sensors[0].LowestValue, Is.EqualTo(3000)); + Assert.That(generated.Sensors[1].LowestValue, Is.EqualTo(8000)); + Assert.That(generated.Sensors[2].LowestValue, Is.EqualTo(12000)); + + Assert.That(generated.Sensors[0].HighestValue, Is.EqualTo(3000)); + Assert.That(generated.Sensors[1].HighestValue, Is.EqualTo(8000)); + Assert.That(generated.Sensors[2].HighestValue, Is.EqualTo(12000)); + + Assert.That(generated.Sensors[0].RecordedValue, Is.EqualTo(0)); + Assert.That(generated.Sensors[1].RecordedValue, Is.EqualTo(0)); + Assert.That(generated.Sensors[2].RecordedValue, Is.EqualTo(0)); + }); + + doTests(generated.Sensors.Values.ToArray()); + #endregion + + #region Test New Sensor Values + Assert.That(generated, Is.Not.Null); + Assert.That(generated.Sensors, Has.Count.EqualTo(5)); + ((MockGeneratedSensor)generated.Sensors[0]).UpdateValue(99); + ((MockGeneratedSensor)generated.Sensors[1]).UpdateValue(122); + ((MockGeneratedSensor)generated.Sensors[2]).UpdateValue(155); + + Assert.Multiple(() => + { + Assert.That(generated.Sensors[0].PresentValue, Is.EqualTo(99)); + Assert.That(generated.Sensors[1].PresentValue, Is.EqualTo(122)); + Assert.That(generated.Sensors[2].PresentValue, Is.EqualTo(155)); + + Assert.That(generated.Sensors[0].LowestValue, Is.EqualTo(99)); + Assert.That(generated.Sensors[1].LowestValue, Is.EqualTo(122)); + Assert.That(generated.Sensors[2].LowestValue, Is.EqualTo(155)); + + Assert.That(generated.Sensors[0].HighestValue, Is.EqualTo(3000)); + Assert.That(generated.Sensors[1].HighestValue, Is.EqualTo(8000)); + Assert.That(generated.Sensors[2].HighestValue, Is.EqualTo(12000)); + }); + doTests(generated.Sensors.Values.ToArray()); + #endregion + + #region Test Recorded Sensor Values + Assert.Multiple(() => + { + Assert.That(generated, Is.Not.Null); + Assert.That(generated.Sensors, Has.Count.EqualTo(5)); + Assert.That(generated.Sensors[0].RecordedValueSupported, Is.True); + Assert.That(generated.Sensors[1].RecordedValueSupported, Is.True); + Assert.That(generated.Sensors[2].RecordedValueSupported, Is.True); + Assert.That(generated.Sensors[0].LowestHighestValueSupported, Is.True); + Assert.That(generated.Sensors[1].LowestHighestValueSupported, Is.True); + Assert.That(generated.Sensors[2].LowestHighestValueSupported, Is.True); + }); + + ((MockGeneratedSensor)generated.Sensors[0]).RecordValue(); + ((MockGeneratedSensor)generated.Sensors[1]).RecordValue(); + ((MockGeneratedSensor)generated.Sensors[2]).RecordValue(); + + ((MockGeneratedSensor)generated.Sensors[0]).UpdateValue(111); + ((MockGeneratedSensor)generated.Sensors[1]).UpdateValue(666); + ((MockGeneratedSensor)generated.Sensors[2]).UpdateValue(987); + + Assert.Multiple(() => + { + Assert.That(generated.Sensors[0].RecordedValue, Is.EqualTo(99)); + Assert.That(generated.Sensors[1].RecordedValue, Is.EqualTo(122)); + Assert.That(generated.Sensors[2].RecordedValue, Is.EqualTo(155)); + + Assert.That(generated.Sensors[0].PresentValue, Is.EqualTo(111)); + Assert.That(generated.Sensors[1].PresentValue, Is.EqualTo(666)); + Assert.That(generated.Sensors[2].PresentValue, Is.EqualTo(987)); + + Assert.That(generated.Sensors[0].LowestValue, Is.EqualTo(99)); + Assert.That(generated.Sensors[1].LowestValue, Is.EqualTo(122)); + Assert.That(generated.Sensors[2].LowestValue, Is.EqualTo(155)); + + Assert.That(generated.Sensors[0].HighestValue, Is.EqualTo(3000)); + Assert.That(generated.Sensors[1].HighestValue, Is.EqualTo(8000)); + Assert.That(generated.Sensors[2].HighestValue, Is.EqualTo(12000)); + }); + doTests(generated.Sensors.Values.ToArray()); + #endregion + + #region Test Reset Sensor Values Set_Request + request.Command = ERDM_Command.SET_COMMAND; + for (byte b = 0; b < 2; b++) + { + request.ParameterData = new byte[] { b }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SENSOR_VALUE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(9)); + Assert.That(response.ParameterData[0], Is.EqualTo(b)); + Assert.That(response.Value, Is.TypeOf(typeof(RDMSensorValue))); + }); + } + #endregion + + #region Test Reset Sensor Values Set_Request (Broadcast) + request.ParameterData = new byte[] { 0xff }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SENSOR_VALUE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(9)); + Assert.That(response.ParameterData[0], Is.EqualTo(0xff)); + Assert.That(response.Value, Is.TypeOf(typeof(RDMSensorValue))); + }); + foreach (var generatedSensor in generated.Sensors.Values) + { + Assert.Multiple(() => + { + Assert.That(generatedSensor, Is.Not.Null); + Sensor remoteSensor = generated.Sensors[generatedSensor.SensorId]; + Assert.That(remoteSensor, Is.Not.Null); + Assert.That(remoteSensor.PresentValue, Is.EqualTo(generatedSensor.PresentValue)); + Assert.That(remoteSensor.LowestValue, Is.EqualTo(generatedSensor.LowestValue)); + Assert.That(remoteSensor.HighestValue, Is.EqualTo(generatedSensor.HighestValue)); + Assert.That(remoteSensor.RecordedValue, Is.EqualTo(generatedSensor.RecordedValue)); + }); + } + #endregion + + void doTests(Sensor[] sensors) + { + foreach (Sensor sensor in sensors) + { + request.ParameterData = new byte[] { sensor.SensorId }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.Multiple(() => + { + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SENSOR_VALUE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(9)); + Assert.That(response.Value, Is.EqualTo(new RDMSensorValue(sensor.SensorId, sensor.PresentValue, sensor.LowestValue, sensor.HighestValue, sensor.RecordedValue))); + }); + } + } + } + [Test, Order(53)] + public void TestGetRECORD_SENSORS() + { + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.RECORD_SENSORS, + SubDevice = SubDevice.Root, + }; + RDMMessage? response = null; + + Assert.That(generated, Is.Not.Null); + Assert.That(generated.Sensors, Has.Count.EqualTo(5)); + + #region Test Recorded Sensor Values Set_Request + for (byte b = 0; b < 2; b++) + { + request.ParameterData = new byte[] { b }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.RECORD_SENSORS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + }); + } + #endregion + + #region Test Recorded Sensor Values Set_Request (Broadcast) + request.ParameterData = new byte[] { 0xff }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.RECORD_SENSORS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + }); + foreach (var generatedSensor in generated.Sensors.Values) + { + Assert.Multiple(() => + { + Assert.That(generatedSensor, Is.Not.Null); + Sensor remoteSensor = generated.Sensors[generatedSensor.SensorId]; + Assert.That(remoteSensor, Is.Not.Null); + Assert.That(remoteSensor.PresentValue, Is.EqualTo(generatedSensor.PresentValue)); + Assert.That(remoteSensor.LowestValue, Is.EqualTo(generatedSensor.LowestValue)); + Assert.That(remoteSensor.HighestValue, Is.EqualTo(generatedSensor.HighestValue)); + Assert.That(remoteSensor.RecordedValue, Is.EqualTo(generatedSensor.RecordedValue)); + }); + } + #endregion + + #region Test Invalid Calls + request.ParameterData = new byte[] { 30 }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.RECORD_SENSORS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + + request.ParameterData = new byte[] { 2 }; + request.Command = ERDM_Command.GET_COMMAND; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.RECORD_SENSORS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.UNSUPPORTED_COMMAND_CLASS)); + #endregion + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestSlotModule.cs b/RDMSharpTests/Devices/Modules/TestSlotModule.cs new file mode 100644 index 0000000..a03499c --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestSlotModule.cs @@ -0,0 +1,232 @@ +using RDMSharp.Metadata; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules +{ + public class TestSlotModule + { + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test, Order(40)] + public void TestGetSLOT_INFO() + { + #region Test Basic + Assert.That(generated, Is.Not.Null); + Assert.That(generated.Slots, Has.Count.EqualTo(5)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.SLOT_INFO, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_INFO)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(5 * generated.Slots.Count)); + Assert.That(response.Value, Is.EqualTo(generated.Slots.Select(s => new RDMSlotInfo(s.Value.SlotId, s.Value.Type, s.Value.Category)))); + #endregion + + #region Test Change Personality + Assert.That(generated, Is.Not.Null); + generated.CurrentPersonality = 2; // Change to personality 2 + Assert.That(generated.Slots, Has.Count.EqualTo(8)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_INFO)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(5 * generated.Slots.Count)); + Assert.That(response.Value, Is.EqualTo(generated.Slots.Select(s => new RDMSlotInfo(s.Value.SlotId, s.Value.Type, s.Value.Category)))); + #endregion + + #region Test Change Personality + Assert.That(generated, Is.Not.Null); + generated.CurrentPersonality = 3; // Change to personality 3 + Assert.That(generated.Slots, Has.Count.EqualTo(9)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_INFO)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(5 * generated.Slots.Count)); + Assert.That(response.Value, Is.EqualTo(generated.Slots.Select(s => new RDMSlotInfo(s.Value.SlotId, s.Value.Type, s.Value.Category)))); + #endregion + + #region Test Invalid Calls + Assert.Throws(typeof(NullReferenceException), () => generated.CurrentPersonality = null); // Change to personality null + Assert.Throws(typeof(ArgumentOutOfRangeException), () => generated.CurrentPersonality = 0); // Change to personality 0 + Assert.Throws(typeof(ArgumentOutOfRangeException), () => generated.CurrentPersonality = 4); // Change to personality 4 + Assert.DoesNotThrow(() => generated.CurrentPersonality = 3); // Change to personality 3 + #endregion + } + + [Test, Order(41)] + public void TestGetDEFAULT_SLOT_VALUE() + { + #region Test Basic + Assert.That(generated, Is.Not.Null); + Assert.That(generated.Slots, Has.Count.EqualTo(5)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.DEFAULT_SLOT_VALUE, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEFAULT_SLOT_VALUE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(3 * generated.Slots.Count)); + Assert.That(response.Value, Is.EqualTo(generated.Slots.Select(s => new RDMDefaultSlotValue(s.Value.SlotId, s.Value.DefaultValue)))); + #endregion + + #region Test Change Personality + Assert.That(generated, Is.Not.Null); + generated.CurrentPersonality = 2; // Change to personality 2 + Assert.That(generated.Slots, Has.Count.EqualTo(8)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEFAULT_SLOT_VALUE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(3 * generated.Slots.Count)); + Assert.That(response.Value, Is.EqualTo(generated.Slots.Select(s => new RDMDefaultSlotValue(s.Value.SlotId, s.Value.DefaultValue)))); + #endregion + + #region Test Change Personality + Assert.That(generated, Is.Not.Null); + generated.CurrentPersonality = 3; // Change to personality 3 + Assert.That(generated.Slots, Has.Count.EqualTo(9)); + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEFAULT_SLOT_VALUE)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(3 * generated.Slots.Count)); + Assert.That(response.Value, Is.EqualTo(generated.Slots.Select(s => new RDMDefaultSlotValue(s.Value.SlotId, s.Value.DefaultValue)))); + #endregion + + #region Test Invalid Calls + Assert.Throws(typeof(NullReferenceException), () => generated.CurrentPersonality = null); // Change to personality null + Assert.Throws(typeof(ArgumentOutOfRangeException), () => generated.CurrentPersonality = 0); // Change to personality 0 + Assert.Throws(typeof(ArgumentOutOfRangeException), () => generated.CurrentPersonality = 4); // Change to personality 4 + Assert.DoesNotThrow(() => generated.CurrentPersonality = 3); // Change to personality 3 + #endregion + } + + [Test, Order(42)] + public void TestGetSLOT_DESCRIPTION() + { + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.SLOT_DESCRIPTION, + SubDevice = SubDevice.Root, + }; + RDMMessage? response = null; + #region Test Basic + Assert.That(generated, Is.Not.Null); + Assert.That(generated.Slots, Has.Count.EqualTo(5)); + doTests(generated.Slots.Values.ToArray()); + #endregion + + #region Test Change Personality 2 + generated.CurrentPersonality = 2; // Change to personality 2 + Assert.That(generated, Is.Not.Null); + Assert.That(generated.Slots, Has.Count.EqualTo(8)); + doTests(generated.Slots.Values.ToArray()); + #endregion + + #region Test Change Personality 3 + generated.CurrentPersonality = 3; // Change to personality 3 + Assert.That(generated, Is.Not.Null); + Assert.That(generated.Slots, Has.Count.EqualTo(9)); + doTests(generated.Slots.Values.ToArray()); + #endregion + + #region Test Invalid Calls + Assert.Throws(typeof(NullReferenceException), () => generated.CurrentPersonality = null); // Change to personality null + Assert.Throws(typeof(ArgumentOutOfRangeException), () => generated.CurrentPersonality = 0); // Change to personality 0 + Assert.Throws(typeof(ArgumentOutOfRangeException), () => generated.CurrentPersonality = 4); // Change to personality 4 + Assert.DoesNotThrow(() => generated.CurrentPersonality = 3); // Change to personality 3 + + request.ParameterData = new byte[] { (byte)((10 >> 8) & 0xFF), (byte)(10 & 0xFF) }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_DESCRIPTION)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + #endregion + + void doTests(Slot[] slots) + { + foreach (Slot slot in slots) + { + request.ParameterData = new byte[] { (byte)((slot.SlotId >> 8) & 0xFF), (byte)(slot.SlotId & 0xFF) }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_DESCRIPTION)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(2 + slot.Description.Length)); + Assert.That(response.Value, Is.EqualTo(new RDMSlotDescription(slot.SlotId, slot.Description))); + } + } + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestSoftwareVersionModule.cs b/RDMSharpTests/Devices/Modules/TestSoftwareVersionModule.cs new file mode 100644 index 0000000..4fbbc6d --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestSoftwareVersionModule.cs @@ -0,0 +1,72 @@ +using RDMSharp.Metadata; +using RDMSharp.RDM.Device.Module; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules +{ + public class TestSoftwareVersionModule + { + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test, Order(32)] + public void TestGetSOFTWARE_VERSION_LABEL() + { + const string SOFTWARE_VERSION_LABEL = "Dummy Software"; + #region Test Basic + Assert.That(generated, Is.Not.Null); + var softwareVersionModule = generated.Modules.OfType().Single(); + Assert.That(softwareVersionModule, Is.Not.Null); + Assert.That(softwareVersionModule.SoftwareVersionLabel, Is.EqualTo(SOFTWARE_VERSION_LABEL)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.SOFTWARE_VERSION_LABEL, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SOFTWARE_VERSION_LABEL)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(SOFTWARE_VERSION_LABEL.Length)); + Assert.That(response.Value, Is.EqualTo(SOFTWARE_VERSION_LABEL)); + #endregion + + #region Test Label changed + softwareVersionModule.SoftwareVersionLabel = "Rem x Ram"; + Assert.That(softwareVersionModule.SoftwareVersionLabel, Is.EqualTo("Rem x Ram")); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SOFTWARE_VERSION_LABEL)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(softwareVersionModule.SoftwareVersionLabel.Length)); + Assert.That(response.Value, Is.EqualTo(softwareVersionModule.SoftwareVersionLabel)); + #endregion + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestStatusMessagesModule.cs b/RDMSharpTests/Devices/Modules/TestStatusMessagesModule.cs new file mode 100644 index 0000000..f866a91 --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestStatusMessagesModule.cs @@ -0,0 +1,230 @@ +using RDMSharp.Metadata; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules +{ + public class TestStatusMessagesModule + { + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test, Order(100)] + public void TestGetSTATUS_MESSAGES() + { + #region Test Empty Status Messages + Assert.That(generated, Is.Not.Null); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.STATUS_MESSAGES, + SubDevice = SubDevice.Root, + ParameterData = new byte[] { (byte)ERDM_Status.ERROR } + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + #endregion + + #region Test Basic Status Messages + generated.AddStatusMessage(new RDMStatusMessage( + subDeviceId: 0, + statusType: ERDM_Status.ERROR, + statusMessage: ERDM_StatusMessage.OVERCURRENT, + dataValue1: 1234, + dataValue2: 5678)); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(9)); + Assert.That(response.Value, Is.TypeOf(typeof(RDMStatusMessage[]))); + RDMStatusMessage[] statusMessages = (RDMStatusMessage[])response.Value; + Assert.That(statusMessages[0], Is.EqualTo(generated.StatusMessages[0])); + + generated.AddStatusMessage(new RDMStatusMessage( + subDeviceId: 0, + statusType: ERDM_Status.ERROR, + statusMessage: ERDM_StatusMessage.UNDERTEMP, + dataValue1: 33, + dataValue2: 12)); + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(18)); + Assert.That(response.Value, Is.TypeOf(typeof(RDMStatusMessage[]))); + statusMessages = (RDMStatusMessage[])response.Value; + Assert.That(statusMessages, Has.Length.EqualTo(2)); + Assert.That(statusMessages[0], Is.EqualTo(generated.StatusMessages[0])); + Assert.That(statusMessages[1], Is.EqualTo(generated.StatusMessages[1])); + #endregion + + #region Test Overflow + for (byte i = 0; i < 30; i++) + { + generated.AddStatusMessage(new RDMStatusMessage( + subDeviceId: i, + statusType: ERDM_Status.ADVISORY, + statusMessage: ERDM_StatusMessage.WATTS, + dataValue1: 33, + dataValue2: 12)); + } + + request.ParameterData = new byte[] { (byte)ERDM_Status.ADVISORY }; + response = generated.ProcessRequestMessage_Internal(request); + + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK_OVERFLOW)); + Assert.That(response.ParameterData, Has.Length.EqualTo(9 * 25)); + Assert.That(response.Value, Is.TypeOf(typeof(RDMStatusMessage[]))); + statusMessages = (RDMStatusMessage[])response.Value; + Assert.That(statusMessages, Has.Length.EqualTo(25)); + for (int i = 0; i < 25; i++) + Assert.That(statusMessages[i], Is.EqualTo(generated.StatusMessages[i])); + + response = generated.ProcessRequestMessage_Internal(request); + + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(9 * 7)); + Assert.That(response.Value, Is.TypeOf(typeof(RDMStatusMessage[]))); + statusMessages = (RDMStatusMessage[])response.Value; + Assert.That(statusMessages, Has.Length.EqualTo(7)); + for (int i = 0; i < 7; i++) + Assert.That(statusMessages[i], Is.EqualTo(generated.StatusMessages[i + 25])); + #endregion + + #region Test GET_LAST_MESSAGE + request.ParameterData = new byte[] { (byte)ERDM_Status.GET_LAST_MESSAGE }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(9 * 7)); + Assert.That(response.Value, Is.TypeOf(typeof(RDMStatusMessage[]))); + statusMessages = (RDMStatusMessage[])response.Value; + Assert.That(statusMessages, Has.Length.EqualTo(7)); + for (int i = 0; i < 7; i++) + Assert.That(statusMessages[i], Is.EqualTo(generated.StatusMessages[i + 25])); + #endregion + + #region Test filtering by status type + request.ParameterData = new byte[] { (byte)ERDM_Status.ERROR }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(18)); + statusMessages = (RDMStatusMessage[])response.Value; + for (int i = 0; i < 2; i++) + Assert.That(statusMessages[i], Is.EqualTo(generated.StatusMessages[i])); + #endregion + + #region Test Cleared Status Messages + generated.ClearStatusMessage(generated.StatusMessages[0]); + request.ParameterData = new byte[] { (byte)ERDM_Status.ERROR }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(18)); + statusMessages = (RDMStatusMessage[])response.Value; + Assert.That(statusMessages[0].EStatusType, Is.EqualTo(ERDM_Status.ERROR_CLEARED)); + for (int i = 0; i < 2; i++) + Assert.That(statusMessages[i], Is.EqualTo(generated.StatusMessages[i])); + #endregion + + #region Test Remove Status Messages + foreach (RDMStatusMessage statusMessage in generated.StatusMessages.Values.ToArray()) + generated.RemoveStatusMessage(statusMessage); + + request.ParameterData = new byte[] { (byte)ERDM_Status.ADVISORY }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + #endregion + + + #region CLEAR_STATUS_ID + generated.AddStatusMessage(new RDMStatusMessage( + subDeviceId: 0, + statusType: ERDM_Status.ERROR, + statusMessage: ERDM_StatusMessage.OVERCURRENT, + dataValue1: 1234, + dataValue2: 5678)); + request.ParameterData = new byte[] { }; + request.Parameter = ERDM_Parameter.CLEAR_STATUS_ID; + request.Command = ERDM_Command.SET_COMMAND; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CLEAR_STATUS_ID)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.MessageCounter, Is.EqualTo(0)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + #endregion + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestSupportedParametersModule.cs b/RDMSharpTests/Devices/Modules/TestSupportedParametersModule.cs new file mode 100644 index 0000000..8bdebf2 --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestSupportedParametersModule.cs @@ -0,0 +1,55 @@ +using RDMSharp.Metadata; +using RDMSharpTests.Devices.Mock; + +namespace RDMSharpTests.RDM.Devices.Modules +{ + public class TestSupportedParametersModule + { + private MockGeneratedDevice1? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new MockGeneratedDevice1(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + [Test, Order(1)] + public void TestGetSUPPORTED_PARAMETERS() + { + #region Test Basic + Assert.That(generated, Is.Not.Null); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.SUPPORTED_PARAMETERS, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SUPPORTED_PARAMETERS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(generated.Parameters.Count * 2)); + Assert.That(response.Value, Is.TypeOf(typeof(ERDM_Parameter[]))); + var parametersRemote = ((ERDM_Parameter[])response.Value).OrderBy(p => p).ToArray(); + var parametersGenerated = generated.Parameters.OrderBy(p => p).ToArray(); + Assert.That(parametersRemote, Is.EquivalentTo(parametersGenerated)); + #endregion + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/Modules/TestTagModlue.cs b/RDMSharpTests/Devices/Modules/TestTagModlue.cs new file mode 100644 index 0000000..22c16dc --- /dev/null +++ b/RDMSharpTests/Devices/Modules/TestTagModlue.cs @@ -0,0 +1,723 @@ +using RDMSharp.Metadata; +using RDMSharp.RDM.Device.Module; +using RDMSharpTests.Devices.Mock; +using System.Text; + +namespace RDMSharpTests.RDM.Devices.Modules; + +public class TestTagModlue +{ + private TagsMockDevice? generated; + + private static UID CONTROLLER_UID = new UID(0x1fff, 333); + private static UID DEVCIE_UID = new UID(123, 555); + [SetUp] + public void Setup() + { + var defines = MetadataFactory.GetMetadataDefineVersions(); + generated = new TagsMockDevice(DEVCIE_UID); + } + [TearDown] + public void TearDown() + { + generated?.Dispose(); + generated = null; + } + + + [Test, Retry(3), Order(1)] + public void TestGetLIST_TAGS() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + var tagsModule = generated.Modules.OfType().FirstOrDefault(); + Assert.That(tagsModule, Is.Not.Null); + Assert.That(tagsModule.Tags, Is.Not.Null); + Assert.That(tagsModule.Tags, Has.Count.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.LIST_TAGS, + SubDevice = SubDevice.Root, + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.LIST_TAGS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + #endregion + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.ADD_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.UTF8.GetBytes("Backtruss") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.ADD_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.LIST_TAGS, + SubDevice = SubDevice.Root, + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.LIST_TAGS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(10)); + + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.ADD_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.UTF8.GetBytes("Center") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.ADD_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.LIST_TAGS, + SubDevice = SubDevice.Root, + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.LIST_TAGS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(17)); + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.CHECK_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.UTF8.GetBytes("Center") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CHECK_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(1)); + Assert.That(response.Value, Is.EqualTo(true)); + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.REMOVE_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.UTF8.GetBytes("Center") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.REMOVE_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.LIST_TAGS, + SubDevice = SubDevice.Root, + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.LIST_TAGS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(10)); + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.CHECK_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.UTF8.GetBytes("Center") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CHECK_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(1)); + Assert.That(response.Value, Is.EqualTo(false)); + + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.CLEAR_TAGS, + SubDevice = SubDevice.Root + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CLEAR_TAGS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.LIST_TAGS, + SubDevice = SubDevice.Root, + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.LIST_TAGS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + } + [Test, Retry(3), Order(2)] + public void TestSetADD_TAG() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + var tagsModule = generated.Modules.OfType().FirstOrDefault(); + Assert.That(tagsModule, Is.Not.Null); + Assert.That(tagsModule.Tags, Is.Not.Null); + Assert.That(tagsModule.Tags, Has.Count.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.ADD_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.ASCII.GetBytes("Backtruss") + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.ADD_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + #endregion + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.ADD_TAG, + SubDevice = SubDevice.Root + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.ADD_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.ADD_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.ASCII.GetBytes(" ") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.ADD_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.ADD_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.ASCII.GetBytes("asdfghjkljhgfdsdfghjhgfdsdfghjjhgfdsdfghjjhgfdfghjhgfdfghjhgfdfghjhgfdfghjjgfdfghj") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.ADD_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.ADD_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.ASCII.GetBytes("GeNeRaTeHaRdWaReFaUlT") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.ADD_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.HARDWARE_FAULT)); + + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.ADD_TAG, + SubDevice = SubDevice.Root, + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.ADD_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.UNSUPPORTED_COMMAND_CLASS)); + } + [Test, Retry(3), Order(3)] + public void TestSetREMOVE_TAG() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + var tagsModule = generated.Modules.OfType().FirstOrDefault(); + Assert.That(tagsModule, Is.Not.Null); + Assert.That(tagsModule.Tags, Is.Not.Null); + Assert.That(tagsModule.Tags, Has.Count.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.REMOVE_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.ASCII.GetBytes("Backtruss") + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.REMOVE_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + #endregion + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.REMOVE_TAG, + SubDevice = SubDevice.Root + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.REMOVE_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.REMOVE_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.ASCII.GetBytes(" ") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.REMOVE_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.REMOVE_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.ASCII.GetBytes("asdfghjkljhgfdsdfghjhgfdsdfghjjhgfdsdfghjjhgfdfghjhgfdfghjhgfdfghjhgfdfghjjgfdfghj") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.REMOVE_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.REMOVE_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.ASCII.GetBytes("GeNeRaTeHaRdWaReFaUlT") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.REMOVE_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.HARDWARE_FAULT)); + + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.REMOVE_TAG, + SubDevice = SubDevice.Root, + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.REMOVE_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.UNSUPPORTED_COMMAND_CLASS)); + } + [Test, Retry(3), Order(3)] + public void TestSetCHECK_TAG() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + var tagsModule = generated.Modules.OfType().FirstOrDefault(); + Assert.That(tagsModule, Is.Not.Null); + Assert.That(tagsModule.Tags, Is.Not.Null); + Assert.That(tagsModule.Tags, Has.Count.EqualTo(0)); + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.CHECK_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.ASCII.GetBytes("Backtruss") + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CHECK_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(1)); + Assert.That(response.Value, Is.False); + #endregion + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.CHECK_TAG, + SubDevice = SubDevice.Root + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CHECK_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.CHECK_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.ASCII.GetBytes(" ") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CHECK_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.FORMAT_ERROR)); + + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.CHECK_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.ASCII.GetBytes("asdfghjkljhgfdsdfghjhgfdsdfghjjhgfdsdfghjjhgfdfghjhgfdfghjhgfdfghjhgfdfghjjgfdfghj") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CHECK_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.DATA_OUT_OF_RANGE)); + + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.CHECK_TAG, + SubDevice = SubDevice.Root, + ParameterData = Encoding.ASCII.GetBytes("GeNeRaTeHaRdWaReFaUlT") + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CHECK_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.HARDWARE_FAULT)); + + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.CHECK_TAG, + SubDevice = SubDevice.Root, + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CHECK_TAG)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.UNSUPPORTED_COMMAND_CLASS)); + } + + [Test, Retry(3), Order(4)] + public void TestSetCLEAR_TAG() + { + #region Test Basic (Empty) + Assert.That(generated, Is.Not.Null); + var tagsModule = generated.Modules.OfType().FirstOrDefault(); + Assert.That(tagsModule, Is.Not.Null); + Assert.That(tagsModule.Tags, Is.Not.Null); + Assert.That(tagsModule.Tags, Has.Count.EqualTo(0)); + + RDMMessage request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.CLEAR_TAGS, + SubDevice = SubDevice.Root + }; + + RDMMessage? response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CLEAR_TAGS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); + Assert.That(response.ParameterData, Has.Length.EqualTo(0)); + #endregion + + request = new RDMMessage() + { + Command = ERDM_Command.SET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = new UID(0xeeee, 0xf0f0f0f0),//Hardware Failure trigger + Parameter = ERDM_Parameter.CLEAR_TAGS, + SubDevice = SubDevice.Root + }; + + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.Not.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CLEAR_TAGS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.HARDWARE_FAULT)); + + request = new RDMMessage() + { + Command = ERDM_Command.GET_COMMAND, + DestUID = DEVCIE_UID, + SourceUID = CONTROLLER_UID, + Parameter = ERDM_Parameter.CLEAR_TAGS, + SubDevice = SubDevice.Root + }; + response = generated.ProcessRequestMessage_Internal(request); + Assert.That(response, Is.Not.Null); + Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND_RESPONSE)); + Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); + Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); + Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CLEAR_TAGS)); + Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); + Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); + Assert.That(response.NackReason, Is.EqualTo(ERDM_NackReason.UNSUPPORTED_COMMAND_CLASS)); + } + + class TagsMockDevice : MockGeneratedDevice1 + { + public TagsMockDevice(UID uid) : base(uid, new IModule[] { new TagsModule() }) + { + } + } +} \ No newline at end of file diff --git a/RDMSharpTests/Devices/TestRDMSendReceive.cs b/RDMSharpTests/Devices/TestRDMSendReceive.cs index f181260..380a81f 100644 --- a/RDMSharpTests/Devices/TestRDMSendReceive.cs +++ b/RDMSharpTests/Devices/TestRDMSendReceive.cs @@ -1,3 +1,4 @@ +using RDMSharp.RDM.Device.Module; using RDMSharpTests.Devices.Mock; namespace RDMSharpTests.RDM.Devices @@ -55,12 +56,15 @@ public async Task TestDevice1() Assert.That(parameterValuesRemote, Has.Count.EqualTo(parameterValuesGenerated.Count)); }); + var deviceLabelModule = generated.Modules.OfType().Single(); + var manufacturerLabelModule = generated.Modules.OfType().Single(); + var deviceModelDescriptionModule = generated.Modules.OfType().Single(); 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(remote.GetAllParameterValues()[ERDM_Parameter.DEVICE_LABEL], Is.EqualTo(deviceLabelModule.DeviceLabel)); + Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.DEVICE_MODEL_DESCRIPTION], Is.EqualTo(deviceModelDescriptionModule.DeviceModelDescription)); + Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.MANUFACTURER_LABEL], Is.EqualTo(manufacturerLabelModule.ManufacturerLabel)); Assert.That(((RDMDMXPersonality)remote.GetAllParameterValues()[ERDM_Parameter.DMX_PERSONALITY]).Index, Is.EqualTo(generated.CurrentPersonality)); }); @@ -83,7 +87,7 @@ public async Task TestDevice1() Assert.Multiple(() => { Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.DEVICE_LABEL], Is.EqualTo(label)); - Assert.That(generated.DeviceLabel, Is.EqualTo(label)); + Assert.That(deviceLabelModule.DeviceLabel, Is.EqualTo(label)); }); Assert.Multiple(async () => { @@ -120,11 +124,11 @@ public void TestDevice1Slots() Assert.Multiple(() => { - Assert.That(slotIntensity, Is.EqualTo(generated!.Personalities[0].Slots[0])); - Assert.That(slotStrobe, Is.EqualTo(generated.Personalities[0].Slots[1])); - Assert.That(slotRed, Is.EqualTo(generated.Personalities[0].Slots[2])); - Assert.That(slotGreen, Is.EqualTo(generated.Personalities[0].Slots[3])); - Assert.That(slotBlue, Is.EqualTo(generated.Personalities[0].Slots[4])); + Assert.That(slotIntensity, Is.EqualTo(generated!.Personalities.ElementAt(0).Slots[0])); + Assert.That(slotStrobe, Is.EqualTo(generated.Personalities.ElementAt(0).Slots[1])); + Assert.That(slotRed, Is.EqualTo(generated.Personalities.ElementAt(0).Slots[2])); + Assert.That(slotGreen, Is.EqualTo(generated.Personalities.ElementAt(0).Slots[3])); + Assert.That(slotBlue, Is.EqualTo(generated.Personalities.ElementAt(0).Slots[4])); Assert.That(slotIntensity, Is.Not.EqualTo(slotStrobe)); Assert.That(slotIntensity, Is.Not.EqualTo(slotRed)); @@ -449,9 +453,11 @@ public async Task TestDevice1QueuedUpdates() Assert.That(parameterValuesRemote[ERDM_Parameter.IDENTIFY_DEVICE], Is.False); await Task.Delay(400); - + + var deviceLabelModule = generated.Modules.OfType().Single(); + generated.DMXAddress = 69; - generated.DeviceLabel = "Test Label QUEUE"; + deviceLabelModule.DeviceLabel = "Test Label QUEUE"; generated.Identify = true; await Task.Delay(400); diff --git a/RDMSharpTests/Devices/TestRDMSendReceiveGeneratedOnly.cs b/RDMSharpTests/Devices/TestRDMSendReceiveGeneratedOnly.cs deleted file mode 100644 index 505e4a2..0000000 --- a/RDMSharpTests/Devices/TestRDMSendReceiveGeneratedOnly.cs +++ /dev/null @@ -1,1700 +0,0 @@ -using RDMSharpTests.Devices.Mock; - -namespace RDMSharpTests.RDM.Devices -{ - public class TestRDMSendReceiveGeneratedOnly - { - private MockGeneratedDevice1? generated; - - private static UID CONTROLLER_UID = new UID(0x1fff, 333); - private static UID DEVCIE_UID = new UID(123, 555); - [SetUp] - public void Setup() - { - generated = new MockGeneratedDevice1(DEVCIE_UID); - } - [TearDown] - public void TearDown() - { - generated?.Dispose(); - generated = null; - } - - - [Test, Order(1)] - public void TestGetSUPPORTED_PARAMETERS() - { - #region Test Basic - Assert.That(generated, Is.Not.Null); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.SUPPORTED_PARAMETERS, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SUPPORTED_PARAMETERS)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(generated.Parameters.Count * 2)); - Assert.That(response.Value, Is.TypeOf(typeof(ERDM_Parameter[]))); - var parametersRemote = ((ERDM_Parameter[])response.Value).OrderBy(p => p).ToArray(); - var parametersGenerated = generated.Parameters.OrderBy(p => p).ToArray(); - Assert.That(parametersRemote, Is.EquivalentTo(parametersGenerated)); - #endregion - } - [Test, Order(5)] - public void TestGetDEVICE_INFO() - { - #region Test Basic - Assert.That(generated, Is.Not.Null); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.DEVICE_INFO, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_INFO)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(19)); - Assert.That(response.Value, Is.EqualTo(generated.DeviceInfo)); - RDMDeviceInfo? deviceInfo = response!.Value as RDMDeviceInfo; - Assert.That(deviceInfo, Is.Not.Null); - Assert.That(deviceInfo.SensorCount, Is.EqualTo(5)); - #endregion - - #region Test Remove Sensors - List sensors = generated.Sensors.Values.ToList(); - foreach (var sensor in sensors) - generated.RemoveSensors(sensor); - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_INFO)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(19)); - Assert.That(response.Value, Is.EqualTo(generated.DeviceInfo)); - deviceInfo = response!.Value as RDMDeviceInfo; - Assert.That(deviceInfo, Is.Not.Null); - Assert.That(deviceInfo.SensorCount, Is.EqualTo(0)); - #endregion - - #region Test Add Sensors - foreach (var sensor in sensors) - generated.AddSensors(sensor); - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_INFO)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(19)); - Assert.That(response.Value, Is.EqualTo(generated.DeviceInfo)); - deviceInfo = response!.Value as RDMDeviceInfo; - Assert.That(deviceInfo, Is.Not.Null); - Assert.That(deviceInfo.SensorCount, Is.EqualTo(5)); - #endregion - } - [Test, Order(6)] - public void TestGetIDENTIFY_DEVICE() - { - #region Test Basic - Assert.That(generated, Is.Not.Null); - Assert.That(generated.Identify, Is.False); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.IDENTIFY_DEVICE, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(1)); - Assert.That(response.Value, Is.EqualTo(generated.Identify)); - #endregion - - #region Test Identify changed (GET) - Assert.That(generated.Identify, Is.False); - generated.Identify = true; - Assert.That(generated.Identify, Is.True); - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(1)); - Assert.That(response.Value, Is.EqualTo(generated.Identify)); - #endregion - - - #region Test Identify changed (SET) - Assert.That(generated.Identify, Is.True); - request.ParameterData = new byte[] { 0x00 }; // Requesting Identify OFF - request.Command = ERDM_Command.SET_COMMAND; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - - Assert.That(generated.Identify, Is.False); - request.Command = ERDM_Command.GET_COMMAND; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(1)); - Assert.That(response.Value, Is.EqualTo(generated.Identify)); - - request.ParameterData = new byte[] { 0x01 }; // Requesting Identify OFF - request.Command = ERDM_Command.SET_COMMAND; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - - Assert.That(generated.Identify, Is.True); - - request.Command = ERDM_Command.GET_COMMAND; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(1)); - Assert.That(response.Value, Is.EqualTo(generated.Identify)); - - #endregion - } - [Test, Order(7)] - public void TestGetDMX_START_ADDRESS() - { - #region Test Basic - Assert.That(generated, Is.Not.Null); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.DMX_START_ADDRESS, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_START_ADDRESS)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(2)); - Assert.That(response.Value, Is.EqualTo(generated.DMXAddress)); - #endregion - - - #region Test Address changed - generated.DMXAddress = 40; - Assert.That(generated.DMXAddress, Is.EqualTo(40)); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_START_ADDRESS)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(2)); - Assert.That(response.Value, Is.EqualTo(generated.DMXAddress)); - #endregion - } - [Test, Order(9)] - public void TestGetDEVICE_LABEL() - { - #region Test Basic - Assert.That(generated, Is.Not.Null); - Assert.That(generated.DeviceLabel, Is.EqualTo("Dummy Device 1")); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.DEVICE_LABEL, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_LABEL)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(generated.DeviceLabel.Length)); - Assert.That(response.Value, Is.EqualTo(generated.DeviceLabel)); - #endregion - - #region Test Label changed - Assert.That(generated.DeviceLabel, Is.EqualTo("Dummy Device 1")); - generated.DeviceLabel = "Rem x Ram"; - Assert.That(generated.DeviceLabel, Is.EqualTo("Rem x Ram")); - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_LABEL)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(generated.DeviceLabel.Length)); - Assert.That(response.Value, Is.EqualTo(generated.DeviceLabel)); - #endregion - } - [Test, Order(10)] - public void TestGetDMX_PERSONALITY_DESCRIPTION() - { - #region Test Basic - Assert.That(generated, Is.Not.Null); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION, - SubDevice = SubDevice.Root, - ParameterData = new byte[] { 0x00 } // Requesting invalid 0 - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); - Assert.That(response.NackReason, Is.EqualTo(new ERDM_NackReason[] { ERDM_NackReason.DATA_OUT_OF_RANGE })); - - for (byte b = 0; b < generated.Personalities.Length; b++) - { - request.ParameterData = new byte[] { (byte)(b + 1) }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - var pers = generated.Personalities[b]; - var expected = new RDMDMXPersonalityDescription(pers.ID, pers.SlotCount, pers.Description); - Assert.That(response.ParameterData, Has.Length.EqualTo(expected.ToPayloadData().Length)); - Assert.That(response.Value, Is.EqualTo(expected)); - Assert.That(((RDMDMXPersonalityDescription)response.Value).Index, Is.EqualTo(expected.Index)); - } - #endregion - } - [Test, Order(11)] - public void TestGetDMX_PERSONALITY() - { - #region Test Basic - Assert.That(generated, Is.Not.Null); - Assert.That(generated.CurrentPersonality, Is.EqualTo(1)); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.DMX_PERSONALITY, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_PERSONALITY)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - var pers = generated.Personalities[0]; - var expected = new RDMDMXPersonality(pers.ID, (byte)generated.Personalities.Count()); - Assert.That(response.ParameterData, Has.Length.EqualTo(expected.ToPayloadData().Length)); - Assert.That(response.Value, Is.EqualTo(expected)); - Assert.That(((RDMDMXPersonality)response.Value).MinIndex, Is.EqualTo(1)); - Assert.That(((RDMDMXPersonality)response.Value).Index, Is.EqualTo(1)); - Assert.That(((RDMDMXPersonality)response.Value).Count, Is.EqualTo(3)); - #endregion - - #region Test Label changed - Assert.That(generated.CurrentPersonality, Is.EqualTo(1)); - generated.CurrentPersonality = 2; - Assert.That(generated.CurrentPersonality, Is.EqualTo(2)); - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_PERSONALITY)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - pers = generated.Personalities[1]; - expected = new RDMDMXPersonality(pers.ID, (byte)generated.Personalities.Count()); - Assert.That(response.ParameterData, Has.Length.EqualTo(expected.ToPayloadData().Length)); - Assert.That(response.Value, Is.EqualTo(expected)); - #endregion - } - [Test, Order(15)] - public void TestGetMANUFACTURER_LABEL() - { - #region Test Basic - Assert.That(generated, Is.Not.Null); - Assert.That(generated.ManufacturerLabel, Is.EqualTo("Dummy Manufacturer 9FFF")); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.MANUFACTURER_LABEL, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.MANUFACTURER_LABEL)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(generated.ManufacturerLabel.Length)); - Assert.That(response.Value, Is.EqualTo(generated.ManufacturerLabel)); - #endregion - } - [Test, Order(16)] - public void TestGetDEVICE_MODEL_DESCRIPTION() - { - #region Test Basic - Assert.That(generated, Is.Not.Null); - Assert.That(generated.DeviceModelDescription, Is.EqualTo("Test Model Description")); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.DEVICE_MODEL_DESCRIPTION, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_MODEL_DESCRIPTION)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(generated.DeviceModelDescription.Length)); - Assert.That(response.Value, Is.EqualTo(generated.DeviceModelDescription)); - #endregion - } - [Test, Order(30)] - public void TestGetBOOT_SOFTWARE_VERSION_ID() - { - #region Test Basic - Assert.That(generated, Is.Not.Null); - Assert.That(generated.ParameterValues[ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID], Is.EqualTo(4660)); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(4)); - Assert.That(response.Value, Is.EqualTo(generated.ParameterValues[ERDM_Parameter.BOOT_SOFTWARE_VERSION_ID])); - #endregion - } - [Test, Order(31)] - public void TestGetBOOT_SOFTWARE_VERSION_LABEL() - { - const string BOOT_SOFTWARE_VERSION_LABEL = "Dummy Bootloader Software"; - #region Test Basic - Assert.That(generated, Is.Not.Null); - Assert.That(generated.BootSoftwareVersionLabel, Is.EqualTo(BOOT_SOFTWARE_VERSION_LABEL)); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(BOOT_SOFTWARE_VERSION_LABEL.Length)); - Assert.That(response.Value, Is.EqualTo(BOOT_SOFTWARE_VERSION_LABEL)); - #endregion - - #region Test Label changed - generated.BootSoftwareVersionLabel = "Rem x Ram"; - Assert.That(generated.BootSoftwareVersionLabel, Is.EqualTo("Rem x Ram")); - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.BOOT_SOFTWARE_VERSION_LABEL)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(generated.BootSoftwareVersionLabel.Length)); - Assert.That(response.Value, Is.EqualTo(generated.BootSoftwareVersionLabel)); - #endregion - } - [Test, Order(32)] - public void TestGetSOFTWARE_VERSION_LABEL() - { - const string SOFTWARE_VERSION_LABEL = "Dummy Software"; - #region Test Basic - Assert.That(generated, Is.Not.Null); - Assert.That(generated.SoftwareVersionLabel, Is.EqualTo(SOFTWARE_VERSION_LABEL)); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.SOFTWARE_VERSION_LABEL, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SOFTWARE_VERSION_LABEL)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(SOFTWARE_VERSION_LABEL.Length)); - Assert.That(response.Value, Is.EqualTo(SOFTWARE_VERSION_LABEL)); - #endregion - - #region Test Label changed - generated.SoftwareVersionLabel = "Rem x Ram"; - Assert.That(generated.SoftwareVersionLabel, Is.EqualTo("Rem x Ram")); - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SOFTWARE_VERSION_LABEL)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(generated.SoftwareVersionLabel.Length)); - Assert.That(response.Value, Is.EqualTo(generated.SoftwareVersionLabel)); - #endregion - } - - [Test, Order(40)] - public void TestGetSLOT_INFO() - { - #region Test Basic - Assert.That(generated, Is.Not.Null); - Assert.That(generated.Slots, Has.Count.EqualTo(5)); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.SLOT_INFO, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_INFO)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(5 * generated.Slots.Count)); - Assert.That(response.Value, Is.EqualTo(generated.Slots.Select(s => new RDMSlotInfo(s.Value.SlotId, s.Value.Type, s.Value.Category)))); - #endregion - - #region Test Change Personality - Assert.That(generated, Is.Not.Null); - generated.CurrentPersonality = 2; // Change to personality 2 - Assert.That(generated.Slots, Has.Count.EqualTo(8)); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_INFO)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(5 * generated.Slots.Count)); - Assert.That(response.Value, Is.EqualTo(generated.Slots.Select(s => new RDMSlotInfo(s.Value.SlotId, s.Value.Type, s.Value.Category)))); - #endregion - - #region Test Change Personality - Assert.That(generated, Is.Not.Null); - generated.CurrentPersonality = 3; // Change to personality 3 - Assert.That(generated.Slots, Has.Count.EqualTo(9)); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_INFO)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(5 * generated.Slots.Count)); - Assert.That(response.Value, Is.EqualTo(generated.Slots.Select(s => new RDMSlotInfo(s.Value.SlotId, s.Value.Type, s.Value.Category)))); - #endregion - - #region Test Invalid Calls - Assert.Throws(typeof(NullReferenceException), () => generated.CurrentPersonality = null); // Change to personality null - Assert.Throws(typeof(ArgumentOutOfRangeException), () => generated.CurrentPersonality = 0); // Change to personality 0 - Assert.Throws(typeof(ArgumentOutOfRangeException), () => generated.CurrentPersonality = 4); // Change to personality 4 - Assert.DoesNotThrow(() => generated.CurrentPersonality = 3); // Change to personality 3 - #endregion - } - - [Test, Order(41)] - public void TestGetDEFAULT_SLOT_VALUE() - { - #region Test Basic - Assert.That(generated, Is.Not.Null); - Assert.That(generated.Slots, Has.Count.EqualTo(5)); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.DEFAULT_SLOT_VALUE, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEFAULT_SLOT_VALUE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(3 * generated.Slots.Count)); - Assert.That(response.Value, Is.EqualTo(generated.Slots.Select(s => new RDMDefaultSlotValue(s.Value.SlotId, s.Value.DefaultValue)))); - #endregion - - #region Test Change Personality - Assert.That(generated, Is.Not.Null); - generated.CurrentPersonality = 2; // Change to personality 2 - Assert.That(generated.Slots, Has.Count.EqualTo(8)); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEFAULT_SLOT_VALUE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(3 * generated.Slots.Count)); - Assert.That(response.Value, Is.EqualTo(generated.Slots.Select(s => new RDMDefaultSlotValue(s.Value.SlotId, s.Value.DefaultValue)))); - #endregion - - #region Test Change Personality - Assert.That(generated, Is.Not.Null); - generated.CurrentPersonality = 3; // Change to personality 3 - Assert.That(generated.Slots, Has.Count.EqualTo(9)); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEFAULT_SLOT_VALUE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(3 * generated.Slots.Count)); - Assert.That(response.Value, Is.EqualTo(generated.Slots.Select(s => new RDMDefaultSlotValue(s.Value.SlotId, s.Value.DefaultValue)))); - #endregion - - #region Test Invalid Calls - Assert.Throws(typeof(NullReferenceException), () => generated.CurrentPersonality = null); // Change to personality null - Assert.Throws(typeof(ArgumentOutOfRangeException), () => generated.CurrentPersonality = 0); // Change to personality 0 - Assert.Throws(typeof(ArgumentOutOfRangeException), () => generated.CurrentPersonality = 4); // Change to personality 4 - Assert.DoesNotThrow(() => generated.CurrentPersonality = 3); // Change to personality 3 - #endregion - } - - [Test, Order(42)] - public void TestGetSLOT_DESCRIPTION() - { - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.SLOT_DESCRIPTION, - SubDevice = SubDevice.Root, - }; - RDMMessage? response = null; - #region Test Basic - Assert.That(generated, Is.Not.Null); - Assert.That(generated.Slots, Has.Count.EqualTo(5)); - doTests(generated.Slots.Values.ToArray()); - #endregion - - #region Test Change Personality 2 - generated.CurrentPersonality = 2; // Change to personality 2 - Assert.That(generated, Is.Not.Null); - Assert.That(generated.Slots, Has.Count.EqualTo(8)); - doTests(generated.Slots.Values.ToArray()); - #endregion - - #region Test Change Personality 3 - generated.CurrentPersonality = 3; // Change to personality 3 - Assert.That(generated, Is.Not.Null); - Assert.That(generated.Slots, Has.Count.EqualTo(9)); - doTests(generated.Slots.Values.ToArray()); - #endregion - - #region Test Invalid Calls - Assert.Throws(typeof(NullReferenceException), () => generated.CurrentPersonality = null); // Change to personality null - Assert.Throws(typeof(ArgumentOutOfRangeException), () => generated.CurrentPersonality = 0); // Change to personality 0 - Assert.Throws(typeof(ArgumentOutOfRangeException), () => generated.CurrentPersonality = 4); // Change to personality 4 - Assert.DoesNotThrow(() => generated.CurrentPersonality = 3); // Change to personality 3 - - request.ParameterData = new byte[] { (byte)((10 >> 8) & 0xFF), (byte)(10 & 0xFF) }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_DESCRIPTION)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); - Assert.That(response.NackReason, Is.EqualTo(new ERDM_NackReason[] { ERDM_NackReason.DATA_OUT_OF_RANGE })); - #endregion - - void doTests(Slot[] slots) - { - foreach (Slot slot in slots) - { - request.ParameterData = new byte[] { (byte)((slot.SlotId >> 8) & 0xFF), (byte)(slot.SlotId & 0xFF) }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_DESCRIPTION)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(2 + slot.Description.Length)); - Assert.That(response.Value, Is.EqualTo(new RDMSlotDescription(slot.SlotId, slot.Description))); - } - } - } - - [Test, Order(51)] - public void TestGetSENSOR_DEFINITION() - { - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.SENSOR_DEFINITION, - SubDevice = SubDevice.Root, - }; - RDMMessage? response = null; - #region Test Basic - Assert.That(generated, Is.Not.Null); - Assert.That(generated.Sensors, Has.Count.EqualTo(5)); - doTests(generated.Sensors.Values.ToArray()); - #endregion - - - #region Test Remove Sensors - - foreach (var sensor in generated.Sensors.Values.ToArray()) - generated.RemoveSensors(sensor); - - request.Command = ERDM_Command.SET_COMMAND; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.Multiple(() => - { - Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SENSOR_DEFINITION)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); - Assert.That(response.NackReason, Is.EqualTo(new ERDM_NackReason[] { ERDM_NackReason.UNKNOWN_PID })); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - }); - - request.Command = ERDM_Command.GET_COMMAND; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.Multiple(() => - { - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SENSOR_DEFINITION)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); - Assert.That(response.NackReason, Is.EqualTo(new ERDM_NackReason[] { ERDM_NackReason.UNKNOWN_PID })); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - }); - #endregion - - void doTests(Sensor[] sensors) - { - foreach (Sensor sensor in sensors) - { - request.ParameterData = new byte[] { sensor.SensorId }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SENSOR_DEFINITION)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(13 + sensor.Description.Length)); - Assert.That(response.Value, Is.EqualTo(new RDMSensorDefinition(sensor.SensorId, sensor.Type, sensor.Unit, sensor.Prefix, sensor.RangeMinimum, sensor.RangeMaximum, sensor.NormalMinimum, sensor.NormalMaximum, sensor.LowestHighestValueSupported, sensor.RecordedValueSupported, sensor.Description))); - } - } - } - - [Test, Order(52)] - public void TestGetSENSOR_VALUE() - { - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.SENSOR_VALUE, - SubDevice = SubDevice.Root, - }; - RDMMessage? response = null; - #region Test Basic - Assert.That(generated, Is.Not.Null); - Assert.Multiple(() => - { - Assert.That(generated.Sensors, Has.Count.EqualTo(5)); - - Assert.That(generated.Sensors[0].LowestValue, Is.EqualTo(3000)); - Assert.That(generated.Sensors[1].LowestValue, Is.EqualTo(8000)); - Assert.That(generated.Sensors[2].LowestValue, Is.EqualTo(12000)); - - Assert.That(generated.Sensors[0].HighestValue, Is.EqualTo(3000)); - Assert.That(generated.Sensors[1].HighestValue, Is.EqualTo(8000)); - Assert.That(generated.Sensors[2].HighestValue, Is.EqualTo(12000)); - - Assert.That(generated.Sensors[0].RecordedValue, Is.EqualTo(0)); - Assert.That(generated.Sensors[1].RecordedValue, Is.EqualTo(0)); - Assert.That(generated.Sensors[2].RecordedValue, Is.EqualTo(0)); - }); - - doTests(generated.Sensors.Values.ToArray()); - #endregion - - #region Test New Sensor Values - Assert.That(generated, Is.Not.Null); - Assert.That(generated.Sensors, Has.Count.EqualTo(5)); - ((MockGeneratedSensor)generated.Sensors[0]).UpdateValue(99); - ((MockGeneratedSensor)generated.Sensors[1]).UpdateValue(122); - ((MockGeneratedSensor)generated.Sensors[2]).UpdateValue(155); - - Assert.Multiple(() => - { - Assert.That(generated.Sensors[0].PresentValue, Is.EqualTo(99)); - Assert.That(generated.Sensors[1].PresentValue, Is.EqualTo(122)); - Assert.That(generated.Sensors[2].PresentValue, Is.EqualTo(155)); - - Assert.That(generated.Sensors[0].LowestValue, Is.EqualTo(99)); - Assert.That(generated.Sensors[1].LowestValue, Is.EqualTo(122)); - Assert.That(generated.Sensors[2].LowestValue, Is.EqualTo(155)); - - Assert.That(generated.Sensors[0].HighestValue, Is.EqualTo(3000)); - Assert.That(generated.Sensors[1].HighestValue, Is.EqualTo(8000)); - Assert.That(generated.Sensors[2].HighestValue, Is.EqualTo(12000)); - }); - doTests(generated.Sensors.Values.ToArray()); - #endregion - - #region Test Recorded Sensor Values - Assert.Multiple(() => - { - Assert.That(generated, Is.Not.Null); - Assert.That(generated.Sensors, Has.Count.EqualTo(5)); - Assert.That(generated.Sensors[0].RecordedValueSupported, Is.True); - Assert.That(generated.Sensors[1].RecordedValueSupported, Is.True); - Assert.That(generated.Sensors[2].RecordedValueSupported, Is.True); - Assert.That(generated.Sensors[0].LowestHighestValueSupported, Is.True); - Assert.That(generated.Sensors[1].LowestHighestValueSupported, Is.True); - Assert.That(generated.Sensors[2].LowestHighestValueSupported, Is.True); - }); - - ((MockGeneratedSensor)generated.Sensors[0]).RecordValue(); - ((MockGeneratedSensor)generated.Sensors[1]).RecordValue(); - ((MockGeneratedSensor)generated.Sensors[2]).RecordValue(); - - ((MockGeneratedSensor)generated.Sensors[0]).UpdateValue(111); - ((MockGeneratedSensor)generated.Sensors[1]).UpdateValue(666); - ((MockGeneratedSensor)generated.Sensors[2]).UpdateValue(987); - - Assert.Multiple(() => - { - Assert.That(generated.Sensors[0].RecordedValue, Is.EqualTo(99)); - Assert.That(generated.Sensors[1].RecordedValue, Is.EqualTo(122)); - Assert.That(generated.Sensors[2].RecordedValue, Is.EqualTo(155)); - - Assert.That(generated.Sensors[0].PresentValue, Is.EqualTo(111)); - Assert.That(generated.Sensors[1].PresentValue, Is.EqualTo(666)); - Assert.That(generated.Sensors[2].PresentValue, Is.EqualTo(987)); - - Assert.That(generated.Sensors[0].LowestValue, Is.EqualTo(99)); - Assert.That(generated.Sensors[1].LowestValue, Is.EqualTo(122)); - Assert.That(generated.Sensors[2].LowestValue, Is.EqualTo(155)); - - Assert.That(generated.Sensors[0].HighestValue, Is.EqualTo(3000)); - Assert.That(generated.Sensors[1].HighestValue, Is.EqualTo(8000)); - Assert.That(generated.Sensors[2].HighestValue, Is.EqualTo(12000)); - }); - doTests(generated.Sensors.Values.ToArray()); - #endregion - - #region Test Reset Sensor Values Set_Request - request.Command = ERDM_Command.SET_COMMAND; - for (byte b = 0; b < 2; b++) - { - request.ParameterData = new byte[] { b }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.Multiple(() => - { - Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SENSOR_VALUE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(9)); - Assert.That(response.ParameterData[0], Is.EqualTo(b)); - Assert.That(response.Value, Is.TypeOf(typeof(RDMSensorValue))); - }); - } - #endregion - - #region Test Reset Sensor Values Set_Request (Broadcast) - request.ParameterData = new byte[] { 0xff }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.Multiple(() => - { - Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SENSOR_VALUE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(9)); - Assert.That(response.ParameterData[0], Is.EqualTo(0xff)); - Assert.That(response.Value, Is.TypeOf(typeof(RDMSensorValue))); - }); - foreach (var generatedSensor in generated.Sensors.Values) - { - Assert.Multiple(() => - { - Assert.That(generatedSensor, Is.Not.Null); - Sensor remoteSensor = generated.Sensors[generatedSensor.SensorId]; - Assert.That(remoteSensor, Is.Not.Null); - Assert.That(remoteSensor.PresentValue, Is.EqualTo(generatedSensor.PresentValue)); - Assert.That(remoteSensor.LowestValue, Is.EqualTo(generatedSensor.LowestValue)); - Assert.That(remoteSensor.HighestValue, Is.EqualTo(generatedSensor.HighestValue)); - Assert.That(remoteSensor.RecordedValue, Is.EqualTo(generatedSensor.RecordedValue)); - }); - } - #endregion - - #region Test Remove Sensors - foreach (var sensor in generated.Sensors.Values.ToArray()) - generated.RemoveSensors(sensor); - - request.ParameterData = new byte[] { 0 }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.Multiple(() => - { - Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SENSOR_VALUE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); - Assert.That(response.NackReason, Is.EqualTo(new ERDM_NackReason[] { ERDM_NackReason.UNKNOWN_PID })); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - }); - - request.Command = ERDM_Command.GET_COMMAND; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.Multiple(() => - { - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SENSOR_VALUE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); - Assert.That(response.NackReason, Is.EqualTo(new ERDM_NackReason[] { ERDM_NackReason.UNKNOWN_PID })); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - }); - #endregion - - void doTests(Sensor[] sensors) - { - foreach (Sensor sensor in sensors) - { - request.ParameterData = new byte[] { sensor.SensorId }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.Multiple(() => - { - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SENSOR_VALUE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(9)); - Assert.That(response.Value, Is.EqualTo(new RDMSensorValue(sensor.SensorId, sensor.PresentValue, sensor.LowestValue, sensor.HighestValue, sensor.RecordedValue))); - }); - } - } - } - [Test, Order(53)] - public void TestGetRECORD_SENSORS() - { - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.SET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.RECORD_SENSORS, - SubDevice = SubDevice.Root, - }; - RDMMessage? response = null; - - Assert.That(generated, Is.Not.Null); - Assert.That(generated.Sensors, Has.Count.EqualTo(5)); - - #region Test Recorded Sensor Values Set_Request - for (byte b = 0; b < 2; b++) - { - request.ParameterData = new byte[] { b }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.Multiple(() => - { - Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.RECORD_SENSORS)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - }); - } - #endregion - - #region Test Recorded Sensor Values Set_Request (Broadcast) - request.ParameterData = new byte[] { 0xff }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.Multiple(() => - { - Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.RECORD_SENSORS)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - }); - foreach (var generatedSensor in generated.Sensors.Values) - { - Assert.Multiple(() => - { - Assert.That(generatedSensor, Is.Not.Null); - Sensor remoteSensor = generated.Sensors[generatedSensor.SensorId]; - Assert.That(remoteSensor, Is.Not.Null); - Assert.That(remoteSensor.PresentValue, Is.EqualTo(generatedSensor.PresentValue)); - Assert.That(remoteSensor.LowestValue, Is.EqualTo(generatedSensor.LowestValue)); - Assert.That(remoteSensor.HighestValue, Is.EqualTo(generatedSensor.HighestValue)); - Assert.That(remoteSensor.RecordedValue, Is.EqualTo(generatedSensor.RecordedValue)); - }); - } - #endregion - - #region Test Invalid Calls - request.ParameterData = new byte[] { 30 }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.RECORD_SENSORS)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); - Assert.That(response.NackReason, Is.EqualTo(new ERDM_NackReason[] { ERDM_NackReason.DATA_OUT_OF_RANGE })); - - request.ParameterData = new byte[] { 2 }; - request.Command = ERDM_Command.GET_COMMAND; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.RECORD_SENSORS)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); - Assert.That(response.NackReason, Is.EqualTo(new ERDM_NackReason[] { ERDM_NackReason.UNSUPPORTED_COMMAND_CLASS })); - #endregion - - #region Test Remove Sensors - foreach (var sensor in generated.Sensors.Values.ToArray()) - generated.RemoveSensors(sensor); - - request.ParameterData = new byte[] { 0 }; - request.Command = ERDM_Command.SET_COMMAND; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.Multiple(() => - { - Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.RECORD_SENSORS)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); - Assert.That(response.NackReason, Is.EqualTo(new ERDM_NackReason[] { ERDM_NackReason.UNKNOWN_PID })); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - }); - #endregion - } - - [Test, Order(100)] - public void TestGetSTATUS_MESSAGES() - { - #region Test Empty Status Messages - Assert.That(generated, Is.Not.Null); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.STATUS_MESSAGES, - SubDevice = SubDevice.Root, - ParameterData = new byte[] { (byte)ERDM_Status.ERROR } - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - #endregion - - #region Test Basic Status Messages - generated.AddStatusMessage(new RDMStatusMessage( - subDeviceId: 0, - statusType: ERDM_Status.ERROR, - statusMessage: ERDM_StatusMessage.OVERCURRENT, - dataValue1: 1234, - dataValue2: 5678)); - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(9)); - Assert.That(response.Value, Is.TypeOf(typeof(RDMStatusMessage[]))); - RDMStatusMessage[] statusMessages = (RDMStatusMessage[])response.Value; - Assert.That(statusMessages[0], Is.EqualTo(generated.StatusMessages[0])); - - generated.AddStatusMessage(new RDMStatusMessage( - subDeviceId: 0, - statusType: ERDM_Status.ERROR, - statusMessage: ERDM_StatusMessage.UNDERTEMP, - dataValue1: 33, - dataValue2: 12)); - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(18)); - Assert.That(response.Value, Is.TypeOf(typeof(RDMStatusMessage[]))); - statusMessages = (RDMStatusMessage[])response.Value; - Assert.That(statusMessages, Has.Length.EqualTo(2)); - Assert.That(statusMessages[0], Is.EqualTo(generated.StatusMessages[0])); - Assert.That(statusMessages[1], Is.EqualTo(generated.StatusMessages[1])); - #endregion - - #region Test Overflow - for (byte i = 0; i < 30; i++) - { - generated.AddStatusMessage(new RDMStatusMessage( - subDeviceId: i, - statusType: ERDM_Status.ADVISORY, - statusMessage: ERDM_StatusMessage.WATTS, - dataValue1: 33, - dataValue2: 12)); - } - - request.ParameterData = new byte[] { (byte)ERDM_Status.ADVISORY }; - response = generated.ProcessRequestMessage_Internal(request); - - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK_OVERFLOW)); - Assert.That(response.ParameterData, Has.Length.EqualTo(9 * 25)); - Assert.That(response.Value, Is.TypeOf(typeof(RDMStatusMessage[]))); - statusMessages = (RDMStatusMessage[])response.Value; - Assert.That(statusMessages, Has.Length.EqualTo(25)); - for (int i = 0; i < 25; i++) - Assert.That(statusMessages[i], Is.EqualTo(generated.StatusMessages[i])); - - response = generated.ProcessRequestMessage_Internal(request); - - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(9 * 7)); - Assert.That(response.Value, Is.TypeOf(typeof(RDMStatusMessage[]))); - statusMessages = (RDMStatusMessage[])response.Value; - Assert.That(statusMessages, Has.Length.EqualTo(7)); - for (int i = 0; i < 7; i++) - Assert.That(statusMessages[i], Is.EqualTo(generated.StatusMessages[i + 25])); - #endregion - - #region Test GET_LAST_MESSAGE - request.ParameterData = new byte[] { (byte)ERDM_Status.GET_LAST_MESSAGE }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(9 * 7)); - Assert.That(response.Value, Is.TypeOf(typeof(RDMStatusMessage[]))); - statusMessages = (RDMStatusMessage[])response.Value; - Assert.That(statusMessages, Has.Length.EqualTo(7)); - for (int i = 0; i < 7; i++) - Assert.That(statusMessages[i], Is.EqualTo(generated.StatusMessages[i + 25])); - #endregion - - #region Test filtering by status type - request.ParameterData = new byte[] { (byte)ERDM_Status.ERROR }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(18)); - statusMessages = (RDMStatusMessage[])response.Value; - for (int i = 0; i < 2; i++) - Assert.That(statusMessages[i], Is.EqualTo(generated.StatusMessages[i])); - #endregion - - #region Test Cleared Status Messages - generated.ClearStatusMessage(generated.StatusMessages[0]); - request.ParameterData = new byte[] { (byte)ERDM_Status.ERROR }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(18)); - statusMessages = (RDMStatusMessage[])response.Value; - Assert.That(statusMessages[0].EStatusType, Is.EqualTo(ERDM_Status.ERROR_CLEARED)); - for (int i = 0; i < 2; i++) - Assert.That(statusMessages[i], Is.EqualTo(generated.StatusMessages[i])); - #endregion - - #region Test Remove Status Messages - foreach (RDMStatusMessage statusMessage in generated.StatusMessages.Values.ToArray()) - generated.RemoveStatusMessage(statusMessage); - - request.ParameterData = new byte[] { (byte)ERDM_Status.ADVISORY }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - #endregion - - - #region CLEAR_STATUS_ID - generated.AddStatusMessage(new RDMStatusMessage( - subDeviceId: 0, - statusType: ERDM_Status.ERROR, - statusMessage: ERDM_StatusMessage.OVERCURRENT, - dataValue1: 1234, - dataValue2: 5678)); - request.ParameterData = new byte[] { }; - request.Parameter = ERDM_Parameter.CLEAR_STATUS_ID; - request.Command = ERDM_Command.SET_COMMAND; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CLEAR_STATUS_ID)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(0)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - #endregion - } - [Test, Order(1000)] - public void TestGetQUEUED_MESSAGE() - { - #region Test Empty queue - Assert.That(generated, Is.Not.Null); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.QUEUED_MESSAGE, - SubDevice = SubDevice.Root, - ParameterData = new byte[] { (byte)ERDM_Status.ADVISORY } - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - #endregion - - #region Test set DMX-Address (single value changed) - Assert.That(generated.DMXAddress, Is.EqualTo(1)); - generated.DMXAddress = 42; - Assert.That(generated.DMXAddress, Is.EqualTo(42)); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_START_ADDRESS)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(1)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(2)); - Assert.That(response.Value, Is.EqualTo(generated.DMXAddress)); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_INFO)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(0)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(19)); - Assert.That(response.Value, Is.EqualTo(generated.DeviceInfo)); - #endregion - - #region Test Get last Message - request.ParameterData = new byte[] { (byte)ERDM_Status.GET_LAST_MESSAGE }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_INFO)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(0)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(19)); - Assert.That(response.Value, Is.EqualTo(generated.DeviceInfo)); - #endregion - - #region Test set DMX-Address (multiple value changed) - Assert.That(generated.DMXAddress, Is.EqualTo(42)); - generated.DMXAddress = 50; - Assert.That(generated.DMXAddress, Is.EqualTo(50)); - generated.DMXAddress = 60; - Assert.That(generated.DMXAddress, Is.EqualTo(60)); - generated.DMXAddress = 70; - Assert.That(generated.DMXAddress, Is.EqualTo(70)); - generated.DMXAddress = 80; - Assert.That(generated.DMXAddress, Is.EqualTo(80)); - - request.ParameterData = new byte[] { (byte)ERDM_Status.ERROR }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_START_ADDRESS)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(1)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(2)); - Assert.That(response.Value, Is.EqualTo(generated.DMXAddress)); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_INFO)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(0)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(19)); - Assert.That(response.Value, Is.EqualTo(generated.DeviceInfo)); - #endregion - - #region Test set DeviceLabel (single value changed) - Assert.That(generated.DeviceLabel, Is.EqualTo("Dummy Device 1")); - generated.DeviceLabel = "Test Device Queued Message 1"; - Assert.That(generated.DeviceLabel, Is.EqualTo("Test Device Queued Message 1")); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_LABEL)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(0)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(generated.DeviceLabel.Length)); - Assert.That(response.Value, Is.EqualTo(generated.DeviceLabel)); - #endregion - - #region Test set Multiple Parameter at once - generated.DeviceLabel = "GG"; - Assert.That(generated.DeviceLabel, Is.EqualTo("GG")); - generated.SetParameter(ERDM_Parameter.IDENTIFY_DEVICE, true); - generated.CurrentPersonality = 2; - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_LABEL)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(13)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(generated.DeviceLabel.Length)); - Assert.That(response.Value, Is.EqualTo(generated.DeviceLabel)); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.IDENTIFY_DEVICE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(12)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(1)); - Assert.That(response.Value, Is.EqualTo(true)); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DMX_PERSONALITY)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(11)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(2)); - Assert.That(response.Value, Is.EqualTo(new RDMDMXPersonality(2, 3))); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_INFO)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(10)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(40)); - Assert.That(response.Value, Is.EqualTo(generated.Personalities[1].Slots.Select(s => new RDMSlotInfo(s.Value.SlotId, s.Value.Type, s.Value.Category)))); - - for (byte b = 0; b < generated.Personalities[1].SlotCount; b++) - { - var slot = generated.Personalities[1].Slots[b]; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.SLOT_DESCRIPTION)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(9 - b)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(generated.Personalities[1].Slots[b].Description.Length + 2)); - Assert.That(response.Value, Is.EqualTo(new RDMSlotDescription(slot.SlotId, slot.Description))); - } - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEFAULT_SLOT_VALUE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(1)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(3 * generated.Personalities[1].Slots.Count)); - Assert.That(response.Value, Is.EqualTo(generated.Personalities[1].Slots.Select(s => new RDMDefaultSlotValue(s.Value.SlotId, s.Value.DefaultValue)))); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.DEVICE_INFO)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(0)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(19)); - Assert.That(response.Value, Is.EqualTo(generated.DeviceInfo)); - - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(0)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - #endregion - - request.ParameterData = new byte[] { (byte)ERDM_Status.ADVISORY }; - var sm = new RDMStatusMessage(0, ERDM_Status.ADVISORY, ERDM_StatusMessage.AMPS, 222); - generated.AddStatusMessage(sm); - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.STATUS_MESSAGES)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(0)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(9)); - Assert.That(response.Value, Is.TypeOf(typeof(RDMStatusMessage[]))); - RDMStatusMessage[] messages = (RDMStatusMessage[])response.Value; - Assert.That(messages[0], Is.EqualTo(sm)); - - #region - request.ParameterData = new byte[] { (byte)ERDM_Status.NONE }; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.QUEUED_MESSAGE)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(0)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.NACK_REASON)); - Assert.That(response.NackReason, Is.EqualTo(new ERDM_NackReason[] { ERDM_NackReason.FORMAT_ERROR })); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - #endregion - - #region CLEAR_STATUS_ID - request.ParameterData = new byte[] { }; - request.Parameter = ERDM_Parameter.CLEAR_STATUS_ID; - request.Command = ERDM_Command.SET_COMMAND; - response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.SET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.CLEAR_STATUS_ID)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.MessageCounter, Is.EqualTo(0)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(0)); - #endregion - } - - [Test, Retry(3), Order(61)] - public async Task TestGetREAL_TIME_CLOCK() - { - TearDown(); - generated = new RealTimeMockDevice(DEVCIE_UID); - await Task.Delay(500); - #region Test Basic - Assert.That(generated, Is.Not.Null); - await Task.Delay(1000); - Assert.That(generated.RealTimeClock.Minute, Is.EqualTo(DateTime.Now.Minute)); - RDMMessage request = new RDMMessage() - { - Command = ERDM_Command.GET_COMMAND, - DestUID = DEVCIE_UID, - SourceUID = CONTROLLER_UID, - Parameter = ERDM_Parameter.REAL_TIME_CLOCK, - SubDevice = SubDevice.Root, - }; - - RDMMessage? response = generated.ProcessRequestMessage_Internal(request); - Assert.That(response, Is.Not.Null); - Assert.That(response.Command, Is.EqualTo(ERDM_Command.GET_COMMAND | ERDM_Command.RESPONSE)); - Assert.That(response.DestUID, Is.EqualTo(CONTROLLER_UID)); - Assert.That(response.SourceUID, Is.EqualTo(DEVCIE_UID)); - Assert.That(response.Parameter, Is.EqualTo(ERDM_Parameter.REAL_TIME_CLOCK)); - Assert.That(response.SubDevice, Is.EqualTo(SubDevice.Root)); - Assert.That(response.ResponseType, Is.EqualTo(ERDM_ResponseType.ACK)); - Assert.That(response.ParameterData, Has.Length.EqualTo(7)); - Assert.That(response.Value, Is.TypeOf(typeof(RDMRealTimeClock))); - var timeGen = new RDMRealTimeClock(generated.RealTimeClock); - var timeRem = (RDMRealTimeClock)response.Value; - Assert.That(timeRem.Year, Is.EqualTo(timeGen.Year)); - Assert.That(timeRem.Month, Is.EqualTo(timeGen.Month)); - Assert.That(timeRem.Day, Is.EqualTo(timeGen.Day)); - Assert.That(timeRem.Minute, Is.EqualTo(timeGen.Minute)); - Assert.That(timeRem.Second, Is.AtLeast(timeGen.Second - 2).And.AtMost(timeGen.Second + 2)); - #endregion - - } - class RealTimeMockDevice : MockGeneratedDevice1 - { - public RealTimeMockDevice(UID uid) : base(uid) - { - } - - public override bool SupportRealTimeClock => true; - } - } -} \ No newline at end of file diff --git a/RDMSharpTests/Devices/TestRDMSendReceiveSubDevices.cs b/RDMSharpTests/Devices/TestRDMSendReceiveSubDevices.cs index e9fd8f8..b739c46 100644 --- a/RDMSharpTests/Devices/TestRDMSendReceiveSubDevices.cs +++ b/RDMSharpTests/Devices/TestRDMSendReceiveSubDevices.cs @@ -1,3 +1,4 @@ +using RDMSharp.RDM.Device.Module; using RDMSharpTests.Devices.Mock; using System; @@ -95,12 +96,16 @@ private async Task PerformTests(AbstractRemoteRDMDevice remote, AbstractGenerate Assert.That(parameterValuesRemote, Has.Count.EqualTo(parameterValuesGenerated.Count)); //}); + var deviceLabelModule = generated.Modules.OfType().Single(); + var manufacturerLabelModule = generated.Modules.OfType().Single(); + var deviceModelDescriptionModule = generated.Modules.OfType().Single(); + //Assert.Multiple(() => //{ Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.DEVICE_INFO], Is.EqualTo(generated.DeviceInfo)); - Assert.That(remote.ParameterValues[ERDM_Parameter.DEVICE_LABEL], Is.EqualTo(generated.DeviceLabel)); - Assert.That(remote.ParameterValues[ERDM_Parameter.DEVICE_MODEL_DESCRIPTION], Is.EqualTo(generated.DeviceModelDescription)); - Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.MANUFACTURER_LABEL], Is.EqualTo(generated.ManufacturerLabel)); + Assert.That(remote.ParameterValues[ERDM_Parameter.DEVICE_LABEL], Is.EqualTo(deviceLabelModule.DeviceLabel)); + Assert.That(remote.ParameterValues[ERDM_Parameter.DEVICE_MODEL_DESCRIPTION], Is.EqualTo(deviceModelDescriptionModule.DeviceModelDescription)); + Assert.That(remote.GetAllParameterValues()[ERDM_Parameter.MANUFACTURER_LABEL], Is.EqualTo(manufacturerLabelModule.ManufacturerLabel)); Assert.That(((RDMDMXPersonality)remote.ParameterValues[ERDM_Parameter.DMX_PERSONALITY]).Index, Is.EqualTo(generated.CurrentPersonality)); //}); @@ -126,7 +131,7 @@ private async Task PerformTests(AbstractRemoteRDMDevice remote, AbstractGenerate //Assert.Multiple(() => //{ Assert.That(remote.ParameterValues[ERDM_Parameter.DEVICE_LABEL], Is.EqualTo(label)); - Assert.That(generated.DeviceLabel, Is.EqualTo(label)); + Assert.That(deviceLabelModule.DeviceLabel, Is.EqualTo(label)); //}); //Assert.Multiple(async () => //{ diff --git a/RDMSharpTests/Metadata/JSON/TestBytesType.cs b/RDMSharpTests/Metadata/JSON/TestBytesType.cs index d6b2a81..90c29ca 100644 --- a/RDMSharpTests/Metadata/JSON/TestBytesType.cs +++ b/RDMSharpTests/Metadata/JSON/TestBytesType.cs @@ -300,7 +300,7 @@ 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)).SelectMany(en => en).ToArray(); - Assert.That(data, Is.EqualTo(new byte[] { 195, 164, 195, 182, 195, 188, 195, 159, 226, 130, 172, 33 })); + Assert.That(data, Is.EqualTo(new byte[] { 63, 63, 63, 63, 63, 33 })); var dataTree = bytesType.ParseDataToPayload(ref data); Assert.That(data, Has.Length.EqualTo(0)); Assert.That(dataTree.Value, Is.Not.Null); diff --git a/RDMSharpTests/Metadata/TestMetadataFactoryStuff.cs b/RDMSharpTests/Metadata/TestMetadataFactoryStuff.cs index d54e3a5..0fd2a04 100644 --- a/RDMSharpTests/Metadata/TestMetadataFactoryStuff.cs +++ b/RDMSharpTests/Metadata/TestMetadataFactoryStuff.cs @@ -1,85 +1,95 @@ using RDMSharp.Metadata; -namespace RDMSharpTests.Metadata +namespace RDMSharpTests.Metadata; + +public class TestMetadataFactoryStuff { - public class TestMetadataFactoryStuff + [SetUp] + public void Setup() { - [SetUp] - public void Setup() - { - Console.OutputEncoding = System.Text.Encoding.Unicode; - } - [TearDown] - public void Teardown() - { - Console.OutputEncoding = System.Text.Encoding.Default; - } + 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 TestMetadataFactoryESTAParameterHaseDefine() + //[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 TestMetadataFactoryESTAParameterHaseDefine() + { + var parameters = Enum.GetValues().Where(p => (ushort)p >= 30).ToList().AsReadOnly(); + Assert.Multiple(() => { - var parameters = Enum.GetValues().Where(p => (ushort)p >= 30).ToList().AsReadOnly(); - Assert.Multiple(() => + foreach (var parameter in parameters) { - foreach (var parameter in parameters) + switch (parameter) { - switch (parameter) - { - case ERDM_Parameter.COMPONENT_SCOPE: - case ERDM_Parameter.SEARCH_DOMAIN: - case ERDM_Parameter.TCP_COMMS_STATUS: - case ERDM_Parameter.BROKER_STATUS: - Assert.Warn("Implement E1.33 Defines!!!"); - continue; - } - var define = MetadataFactory.GetDefine(new ParameterBag(parameter)); - Assert.That(define, Is.Not.Null, $"Parameter: {parameter} has no matchig Define"); + case ERDM_Parameter.QUEUED_MESSAGE_SENSOR_SUBSCRIBE: + case ERDM_Parameter.SUPPORTED_PARAMETERS_ENHANCED: + case ERDM_Parameter.CONTROLLER_FLAG_SUPPORT: + case ERDM_Parameter.NACK_DESCRIPTION: + case ERDM_Parameter.PACKED_PID_SUB: + case ERDM_Parameter.PACKED_PID_INDEX: + case ERDM_Parameter.ENUM_LABEL: + case ERDM_Parameter.SELFTEST_ENHANCED: + Assert.Warn("Implement E1.20-2025 Defines!!!"); + continue; + + case ERDM_Parameter.COMPONENT_SCOPE: + case ERDM_Parameter.SEARCH_DOMAIN: + case ERDM_Parameter.TCP_COMMS_STATUS: + case ERDM_Parameter.BROKER_STATUS: + Assert.Warn("Implement E1.33 Defines!!!"); + continue; } - }); - } + var define = MetadataFactory.GetDefine(new ParameterBag(parameter)); + Assert.That(define, Is.Not.Null, $"Parameter: {parameter} has no matchig Define"); + } + }); + } - [Test] - public void TestMetadataVersion() + [Test] + public void TestMetadataVersion() + { + var mv = new MetadataVersion("RDMSharp.Resources.JSON_Defines._1._0._0.Defines.e1._20.BOOT_SOFTWARE_VERSION_ID.json", typeof(MetadataFactory).Assembly); + testString(mv.ToString()); + Assert.Multiple(() => { - var mv = new MetadataVersion("RDMSharp.Resources.JSON_Defines._1._0._0.Defines.e1._20.BOOT_SOFTWARE_VERSION_ID.json", typeof(MetadataFactory).Assembly); - 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(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")); - }); - } + 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, typeof(MetadataFactory).Assembly)); - } - 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("}")); - } + [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, typeof(MetadataFactory).Assembly)); + } + 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/TestPeerToPeerProcess.cs b/RDMSharpTests/Metadata/TestPeerToPeerProcess.cs index 9f9cddb..4d35b04 100644 --- a/RDMSharpTests/Metadata/TestPeerToPeerProcess.cs +++ b/RDMSharpTests/Metadata/TestPeerToPeerProcess.cs @@ -1,293 +1,302 @@ using RDMSharp.Metadata; -namespace RDMSharpTests.Metadata +namespace RDMSharpTests.Metadata; + +public class TestPeerToPeerProcess { - public class TestPeerToPeerProcess + + [Test, MaxTime(6000)] + 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); + + try + { + await peerToPeerProcess.Run(helper); - [Test, MaxTime(6000)] - public async Task Test_Get_DMX_START_ADDRESS() + 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)); + Assert.That(peerToPeerProcess.Exception, Is.Null); + } + finally { - 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); + helper?.Dispose(); + helper = null; + } - try - { - await peerToPeerProcess.Run(helper); - - 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)); - Assert.That(peerToPeerProcess.Exception, Is.Null); - } - finally - { - helper?.Dispose(); - helper = null; - } + 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)); - async Task sendMessage(RDMMessage message) + RDMMessage response = new RDMMessage() { - 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, - TransactionCounter = message.TransactionCounter, - ParameterData = MetadataFactory.GetResponseMessageData(parameterBag, new DataTreeBranch(new DataTree[] { new DataTree("dmx_address", 0, DMX_ADDRESS) })).First() - }; + Command = message.Command | ERDM_Command.RESPONSE, + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + SubDevice = message.SubDevice, + TransactionCounter = message.TransactionCounter, + ParameterData = MetadataFactory.GetResponseMessageData(parameterBag, new DataTreeBranch(new DataTree[] { new DataTree("dmx_address", 0, DMX_ADDRESS) })).First() + }; - await Task.Delay(10); - helper?.ReceiveMessage(response); - } + await Task.Delay(10); + helper?.ReceiveMessage(response); } + } - [Test, MaxTime(6000)] - public async Task Test_Get_PROXIED_DEVICES() + [Test, MaxTime(6000)] + 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); + Assert.That(peerToPeerProcess.Exception, Is.Null); + + AsyncRDMRequestHelper? helper = null; + byte[] parameterData = MetadataFactory.GetResponseMessageData(parameterBag, new DataTreeBranch(new DataTree[] { new DataTree("device_uids", 0, children: children) })).SelectMany(en => en).ToArray(); + helper = new AsyncRDMRequestHelper(sendMessage); + + try { - 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); - Assert.That(peerToPeerProcess.Exception, Is.Null); + await peerToPeerProcess.Run(helper); - AsyncRDMRequestHelper? helper = null; - byte[] parameterData = MetadataFactory.GetResponseMessageData(parameterBag, new DataTreeBranch(new DataTree[] { new DataTree("device_uids", 0, children: children) })).SelectMany(en=>en).ToArray(); - helper = new AsyncRDMRequestHelper(sendMessage); + 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(new RDMProxiedDevices(children.Select(dt => (UID)dt.Value!).ToArray()))); + } + finally + { + helper?.Dispose(); + helper = null; + } - try + 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() { - await peerToPeerProcess.Run(helper); + Command = message.Command | ERDM_Command.RESPONSE, + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = message.Parameter, + SubDevice = message.SubDevice, + TransactionCounter = message.TransactionCounter, + ParameterData = _parameterData, + PortID_or_Responsetype = parameterData.Length == 0 ? (byte)ERDM_ResponseType.ACK : (byte)ERDM_ResponseType.ACK_OVERFLOW + }; - 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())); - } - finally - { - helper?.Dispose(); - helper = null; - } + await Task.Delay(10); + helper?.ReceiveMessage(response); + } + } + [Test, MaxTime(6000)] + 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); + Assert.That(peerToPeerProcess.Exception, Is.Null); + + AsyncRDMRequestHelper? helper = null; + byte count = 0; + + try + { + helper = new AsyncRDMRequestHelper(sendMessage); - 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)); + await peerToPeerProcess.Run(helper); - var count = Math.Min(parameterData.Length, 0xE4); - var _parameterData = parameterData.Take(count).ToArray(); - parameterData= parameterData.Skip(count).ToArray(); - RDMMessage response = new RDMMessage() + 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)); + Assert.That(peerToPeerProcess.Exception, Is.Null); + } + finally + { + helper?.Dispose(); + helper = null; + } + 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 = count == 0 ? + new RDMMessage(new AcknowledgeTimer(TimeSpan.FromSeconds(3))) { Command = message.Command | ERDM_Command.RESPONSE, DestUID = message.SourceUID, SourceUID = message.DestUID, - Parameter = message.Parameter, + Parameter = parameterBag.PID, SubDevice = message.SubDevice, TransactionCounter = message.TransactionCounter, - ParameterData = _parameterData, - PortID_or_Responsetype = parameterData.Length == 0 ? (byte)ERDM_ResponseType.ACK : (byte)ERDM_ResponseType.ACK_OVERFLOW - }; + } : + new RDMMessage() + { + Command = message.Command | ERDM_Command.RESPONSE, + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = parameterBag.PID, + SubDevice = message.SubDevice, + TransactionCounter = message.TransactionCounter, + ParameterData = MetadataFactory.GetResponseMessageData(parameterBag, new DataTreeBranch(new DataTree[] { new DataTree("strikes", 0, LAMP_STRIKES) })).First(), + PortID_or_Responsetype = (byte)ERDM_ResponseType.ACK + }; - await Task.Delay(10); - helper?.ReceiveMessage(response); - } + await Task.Delay(10); + count++; + helper?.ReceiveMessage(response); } - [Test, MaxTime(6000)] - public async Task Test_Get_LAMP_STRIKES() + } + [Test, MaxTime(6000)] + public async Task Test_Get_SLOT_INFO() + { + var command = ERDM_Command.GET_COMMAND; + var uid = new UID(1234, 123456); + var subdevice = SubDevice.Root; + var parameterBag = new ParameterBag(ERDM_Parameter.SLOT_INFO); + byte[] SLOT_INFO_1 = new byte[] { + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x00, + 0x03, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x05, + 0x03, 0x00, 0x05, 0x00, 0x05, 0x02, 0x00, 0x06, + 0x00, 0x91, 0x00, 0x00, 0x07, 0x00, 0x91, 0x01, + 0x00, 0x08, 0x00, 0x05, 0x02, 0x00, 0x09, 0x00, + 0x02, 0x01, 0x00, 0x0a, 0x01, 0x00, 0x09, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00, 0x0c, 0x01, 0x00, + 0x0b, 0x00, 0x0d, 0x00, 0x02, 0x02, 0x00, 0x0e, + 0x00, 0x02, 0x04, 0x00, 0x0f, 0x00, 0x02, 0x03, + 0x00, 0x10, 0x00, 0x02, 0x08, 0x00, 0x11, 0x00, + 0x02, 0x08, 0x00, 0x12, 0x00, 0x05, 0x04, 0x00, + 0x13, 0x00, 0x05, 0x03, 0x00, 0x14, 0x00, 0xff, + 0xff, 0x00, 0x15, 0x00, 0xff, 0xff, 0x00, 0x16, + 0x00, 0x03, 0x04, 0x00, 0x17, 0x06, 0x00, 0x16, + 0x00, 0x18, 0x04, 0x00, 0x17 + }; + byte[] SLOT_INFO_2 = new byte[] { + 0x00, 0x19, 0x00, 0x03, 0x02, 0x00, 0x1a, 0x07, + 0x00, 0x19, 0x00, 0x1b, 0x01, 0x00, 0x1a, 0x00, + 0x1c, 0x00, 0x03, 0x02, 0x00, 0x1d, 0x07, 0x00, + 0x1c, 0x00, 0x1e, 0x01, 0x00, 0x1d, 0x00, 0x1f, + 0x00, 0x03, 0x03, 0x00, 0x20, 0x06, 0x00, 0x1f, + 0x00, 0x21, 0x00, 0x03, 0x03, 0x00, 0x22, 0x06, + 0x00, 0x21, 0x00, 0x23, 0x00, 0x04, 0x03, 0x00, + 0x24, 0x00, 0x04, 0x01, 0x00, 0x25, 0x01, 0x00, + 0x24, 0x00, 0x26, 0x00, 0x04, 0x05, 0x00, 0x27, + 0x01, 0x00, 0x26, 0x00, 0x28, 0x00, 0x04, 0x02, + 0x00, 0x29, 0x01, 0x00, 0x28, 0x00, 0x2a, 0x00, + 0x04, 0x06, 0x00, 0x2b, 0x00, 0x04, 0x06, 0x00, + 0x2c, 0x06, 0x00, 0x2b, 0x00, 0x2d, 0x00, 0x04, + 0x06, 0x00, 0x2e, 0x06, 0x00, 0x2d, 0x00, 0x2f, + 0x00, 0x04, 0x06, 0x00, 0x30, 0x06, 0x00, 0x2f, + 0x00, 0x31, 0x00, 0x04, 0x06, 0x00, 0x32, 0x06, + 0x00, 0x31, 0x00, 0x33, 0x00, 0x04, 0x04, 0x00, + 0x34, 0x00, 0x00, 0x02, 0x00, 0x35, 0x01, 0x00, + 0x34 + }; + 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); + Assert.That(peerToPeerProcess.Exception, Is.Null); + + AsyncRDMRequestHelper? helper = null; + byte count = 0; + + try { - 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); - Assert.That(peerToPeerProcess.Exception, Is.Null); - - AsyncRDMRequestHelper? helper = null; - byte count = 0; - - try - { - helper = new AsyncRDMRequestHelper(sendMessage); + helper = new AsyncRDMRequestHelper(sendMessage); - await peerToPeerProcess.Run(helper); + await peerToPeerProcess.Run(helper); - 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)); - Assert.That(peerToPeerProcess.Exception, Is.Null); - } - finally - { - helper?.Dispose(); - helper = null; - } - 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, - TransactionCounter= message.TransactionCounter, - ParameterData = count == 0 ? new AcknowledgeTimer(TimeSpan.FromSeconds(3)).ToPayloadData() : MetadataFactory.GetResponseMessageData(parameterBag, new DataTreeBranch(new DataTree[] { new DataTree("strikes", 0, LAMP_STRIKES) })).First(), - PortID_or_Responsetype = count == 0 ? (byte)ERDM_ResponseType.ACK_TIMER : (byte)ERDM_ResponseType.ACK - }; - - await Task.Delay(10); - count++; - helper?.ReceiveMessage(response); - } + Assert.That(peerToPeerProcess.ResponsePayloadObject, Is.TypeOf(typeof(DataTreeBranch))); + Assert.That(peerToPeerProcess.ResponsePayloadObject.ParsedObject, Is.Not.Null); + Assert.That(peerToPeerProcess.ResponsePayloadObject.ParsedObject, Is.TypeOf(typeof(RDMSlotInfo[]))); + RDMSlotInfo[] slotInfos = (RDMSlotInfo[])peerToPeerProcess.ResponsePayloadObject.ParsedObject; + Assert.That(slotInfos, Has.Length.EqualTo(54)); + Assert.That(peerToPeerProcess.Exception, Is.Null); } - [Test, MaxTime(6000)] - public async Task Test_Get_SLOT_INFO() + finally { - var command = ERDM_Command.GET_COMMAND; - var uid = new UID(1234, 123456); - var subdevice = SubDevice.Root; - var parameterBag = new ParameterBag(ERDM_Parameter.SLOT_INFO); - byte[] SLOT_INFO_1 = new byte[] { - 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x00, - 0x03, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x05, - 0x03, 0x00, 0x05, 0x00, 0x05, 0x02, 0x00, 0x06, - 0x00, 0x91, 0x00, 0x00, 0x07, 0x00, 0x91, 0x01, - 0x00, 0x08, 0x00, 0x05, 0x02, 0x00, 0x09, 0x00, - 0x02, 0x01, 0x00, 0x0a, 0x01, 0x00, 0x09, 0x00, - 0x0b, 0x00, 0x02, 0x01, 0x00, 0x0c, 0x01, 0x00, - 0x0b, 0x00, 0x0d, 0x00, 0x02, 0x02, 0x00, 0x0e, - 0x00, 0x02, 0x04, 0x00, 0x0f, 0x00, 0x02, 0x03, - 0x00, 0x10, 0x00, 0x02, 0x08, 0x00, 0x11, 0x00, - 0x02, 0x08, 0x00, 0x12, 0x00, 0x05, 0x04, 0x00, - 0x13, 0x00, 0x05, 0x03, 0x00, 0x14, 0x00, 0xff, - 0xff, 0x00, 0x15, 0x00, 0xff, 0xff, 0x00, 0x16, - 0x00, 0x03, 0x04, 0x00, 0x17, 0x06, 0x00, 0x16, - 0x00, 0x18, 0x04, 0x00, 0x17 - }; - byte[] SLOT_INFO_2 = new byte[] { - 0x00, 0x19, 0x00, 0x03, 0x02, 0x00, 0x1a, 0x07, - 0x00, 0x19, 0x00, 0x1b, 0x01, 0x00, 0x1a, 0x00, - 0x1c, 0x00, 0x03, 0x02, 0x00, 0x1d, 0x07, 0x00, - 0x1c, 0x00, 0x1e, 0x01, 0x00, 0x1d, 0x00, 0x1f, - 0x00, 0x03, 0x03, 0x00, 0x20, 0x06, 0x00, 0x1f, - 0x00, 0x21, 0x00, 0x03, 0x03, 0x00, 0x22, 0x06, - 0x00, 0x21, 0x00, 0x23, 0x00, 0x04, 0x03, 0x00, - 0x24, 0x00, 0x04, 0x01, 0x00, 0x25, 0x01, 0x00, - 0x24, 0x00, 0x26, 0x00, 0x04, 0x05, 0x00, 0x27, - 0x01, 0x00, 0x26, 0x00, 0x28, 0x00, 0x04, 0x02, - 0x00, 0x29, 0x01, 0x00, 0x28, 0x00, 0x2a, 0x00, - 0x04, 0x06, 0x00, 0x2b, 0x00, 0x04, 0x06, 0x00, - 0x2c, 0x06, 0x00, 0x2b, 0x00, 0x2d, 0x00, 0x04, - 0x06, 0x00, 0x2e, 0x06, 0x00, 0x2d, 0x00, 0x2f, - 0x00, 0x04, 0x06, 0x00, 0x30, 0x06, 0x00, 0x2f, - 0x00, 0x31, 0x00, 0x04, 0x06, 0x00, 0x32, 0x06, - 0x00, 0x31, 0x00, 0x33, 0x00, 0x04, 0x04, 0x00, - 0x34, 0x00, 0x00, 0x02, 0x00, 0x35, 0x01, 0x00, - 0x34 - }; - 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); - Assert.That(peerToPeerProcess.Exception, Is.Null); + helper?.Dispose(); + helper = null; + } + async Task sendMessage(RDMMessage message) + { + Assert.That(count, Is.LessThan(2)); - AsyncRDMRequestHelper? helper = null; - byte count = 0; + Assert.That(message.Command, Is.EqualTo(command)); + Assert.That(message.DestUID, Is.EqualTo(uid)); + Assert.That(message.SubDevice, Is.EqualTo(subdevice)); - try - { - helper = new AsyncRDMRequestHelper(sendMessage); - - await peerToPeerProcess.Run(helper); - - Assert.That(peerToPeerProcess.ResponsePayloadObject, Is.TypeOf(typeof(DataTreeBranch))); - Assert.That(peerToPeerProcess.ResponsePayloadObject.ParsedObject, Is.Not.Null); - Assert.That(peerToPeerProcess.ResponsePayloadObject.ParsedObject, Is.TypeOf(typeof(RDMSlotInfo[]))); - RDMSlotInfo[] slotInfos = (RDMSlotInfo[])peerToPeerProcess.ResponsePayloadObject.ParsedObject; - Assert.That(slotInfos, Has.Length.EqualTo(54)); - Assert.That(peerToPeerProcess.Exception, Is.Null); - } - finally - { - helper?.Dispose(); - helper = null; - } - async Task sendMessage(RDMMessage message) + RDMMessage response = new RDMMessage() { - Assert.That(count, Is.LessThan(2)); - - Assert.That(message.Command, Is.EqualTo(command)); - Assert.That(message.DestUID, Is.EqualTo(uid)); - Assert.That(message.SubDevice, Is.EqualTo(subdevice)); + Command = message.Command | ERDM_Command.RESPONSE, + DestUID = message.SourceUID, + SourceUID = message.DestUID, + Parameter = parameterBag.PID, + SubDevice = message.SubDevice, + TransactionCounter = message.TransactionCounter, + ParameterData = count % 2 == 0 ? SLOT_INFO_1 : SLOT_INFO_2, + PortID_or_Responsetype = count % 2 == 0 ? (byte)ERDM_ResponseType.ACK_OVERFLOW : (byte)ERDM_ResponseType.ACK + }; - RDMMessage response = new RDMMessage() - { - Command = message.Command | ERDM_Command.RESPONSE, - DestUID = message.SourceUID, - SourceUID = message.DestUID, - Parameter = parameterBag.PID, - SubDevice = message.SubDevice, - TransactionCounter = message.TransactionCounter, - ParameterData = count % 2 == 0 ? SLOT_INFO_1 : SLOT_INFO_2, - PortID_or_Responsetype = count % 2 == 0 ? (byte)ERDM_ResponseType.ACK_OVERFLOW : (byte)ERDM_ResponseType.ACK - }; - - await Task.Delay(10); - count++; - helper?.ReceiveMessage(response); - } + await Task.Delay(10); + count++; + helper?.ReceiveMessage(response); } } } \ No newline at end of file diff --git a/RDMSharpTests/RDM/PayloadObject/AcknowledgeTimerTest.cs b/RDMSharpTests/RDM/PayloadObject/AcknowledgeTimerTest.cs index 49b5ede..add7797 100644 --- a/RDMSharpTests/RDM/PayloadObject/AcknowledgeTimerTest.cs +++ b/RDMSharpTests/RDM/PayloadObject/AcknowledgeTimerTest.cs @@ -1,43 +1,40 @@ -namespace RDMSharpTests.RDM.PayloadObject +namespace RDMSharpTests.RDM.PayloadObject; + +public class AcknowledgeTimerTest { - public class AcknowledgeTimerTest + [SetUp] + public void Setup() { - [SetUp] - public void Setup() - { - } + } - [Test] - public void ToPayloadAndFromMessageTest() - { - var time = TimeSpan.FromSeconds(3); - AcknowledgeTimer acknowledgeTimer = new AcknowledgeTimer(time); - byte[] data = acknowledgeTimer.ToPayloadData(); + [Test] + public void ToPayloadAndFromMessageTest() + { + var time = TimeSpan.FromSeconds(3); + AcknowledgeTimer acknowledgeTimer = new AcknowledgeTimer(time); - RDMMessage message = new RDMMessage() - { - PortID_or_Responsetype = (byte)ERDM_ResponseType.ACK_TIMER, - Command = ERDM_Command.GET_COMMAND_RESPONSE, - Parameter = ERDM_Parameter.LAMP_STRIKES, - ParameterData = data, - }; + RDMMessage message = new RDMMessage(acknowledgeTimer) + { + PortID_or_Responsetype = (byte)ERDM_ResponseType.ACK_TIMER, + Command = ERDM_Command.GET_COMMAND_RESPONSE, + Parameter = ERDM_Parameter.LAMP_STRIKES, + }; - AcknowledgeTimer resultAcknowledgeTimer = AcknowledgeTimer.FromMessage(message); - Assert.Throws(typeof(RDMMessageInvalidPDLException), () => { AcknowledgeTimer.FromPayloadData(data.ToList().Concat(new byte[1]).ToArray()); }); + AcknowledgeTimer resultAcknowledgeTimer = AcknowledgeTimer.FromMessage(message); + Assert.Throws(typeof(RDMMessageInvalidPDLException), () => { AcknowledgeTimer.FromPayloadData(new byte[2].ToList().Concat(new byte[1]).ToArray()); }); - Assert.That(resultAcknowledgeTimer, Is.EqualTo(acknowledgeTimer)); - Assert.That(resultAcknowledgeTimer.EstimidatedResponseTime, Is.EqualTo(time)); + Assert.That(resultAcknowledgeTimer, Is.EqualTo(acknowledgeTimer)); + Assert.That(resultAcknowledgeTimer.EstimidatedResponseTime, Is.EqualTo(time)); - Assert.Throws(typeof(ArgumentOutOfRangeException), () => { new AcknowledgeTimer(TimeSpan.FromSeconds(3600000)); }); + Assert.Throws(typeof(ArgumentOutOfRangeException), () => { new AcknowledgeTimer(TimeSpan.FromSeconds(3600000)); }); - var res = resultAcknowledgeTimer.ToString(); - var src = acknowledgeTimer.ToString(); - Assert.Multiple(() => - { - Assert.That(res, Is.Not.Null); - Assert.That(src, Is.Not.Null); - Assert.That(res, Is.EqualTo(src)); - }); - } + var res = resultAcknowledgeTimer.ToString(); + var src = acknowledgeTimer.ToString(); + Assert.Multiple(() => + { + Assert.That(res, Is.Not.Null); + Assert.That(src, Is.Not.Null); + Assert.That(res, Is.EqualTo(src)); + }); } } \ No newline at end of file diff --git a/RDMSharpTests/RDM/PayloadObject/GetInterfaceListResponseTest.cs b/RDMSharpTests/RDM/PayloadObject/GetInterfaceListResponseTest.cs index d0cc63c..82d481c 100644 --- a/RDMSharpTests/RDM/PayloadObject/GetInterfaceListResponseTest.cs +++ b/RDMSharpTests/RDM/PayloadObject/GetInterfaceListResponseTest.cs @@ -1,51 +1,51 @@ -namespace RDMSharpTests.RDM.PayloadObject -{ - public class GetInterfaceListResponseTest - { - [SetUp] - public void Setup() - { - } +//namespace RDMSharpTests.RDM.PayloadObject +//{ +// public class GetInterfaceListResponseTest +// { +// [SetUp] +// public void Setup() +// { +// } - [Test] - public void ToPayloadAndFromMessageTest() - { - GetInterfaceListResponse getInterfaceListResponse = new GetInterfaceListResponse( - new InterfaceDescriptor(), - new InterfaceDescriptor(1, 1), - new InterfaceDescriptor(1, 2), - new InterfaceDescriptor(1, 3), - new InterfaceDescriptor(2, 1), - new InterfaceDescriptor(2, 2), - new InterfaceDescriptor(2, 3), - new InterfaceDescriptor(3, 1), - new InterfaceDescriptor(3, 2), - new InterfaceDescriptor(3, 3)); +// [Test] +// public void ToPayloadAndFromMessageTest() +// { +// GetInterfaceListResponse getInterfaceListResponse = new GetInterfaceListResponse( +// new InterfaceDescriptor(), +// new InterfaceDescriptor(1, 1), +// new InterfaceDescriptor(1, 2), +// new InterfaceDescriptor(1, 3), +// new InterfaceDescriptor(2, 1), +// new InterfaceDescriptor(2, 2), +// new InterfaceDescriptor(2, 3), +// new InterfaceDescriptor(3, 1), +// new InterfaceDescriptor(3, 2), +// new InterfaceDescriptor(3, 3)); - byte[] data = getInterfaceListResponse.ToPayloadData(); +// byte[] data = getInterfaceListResponse.ToPayloadData(); - RDMMessage message = new RDMMessage() - { - PortID_or_Responsetype = (byte)ERDM_ResponseType.ACK, - Command = ERDM_Command.GET_COMMAND_RESPONSE, - Parameter = ERDM_Parameter.LIST_INTERFACES, - ParameterData = data, - }; +// RDMMessage message = new RDMMessage() +// { +// PortID_or_Responsetype = (byte)ERDM_ResponseType.ACK, +// Command = ERDM_Command.GET_COMMAND_RESPONSE, +// Parameter = ERDM_Parameter.LIST_INTERFACES, +// ParameterData = data, +// }; - GetInterfaceListResponse resultGetInterfaceListResponse = GetInterfaceListResponse.FromMessage(message); - Assert.Throws(typeof(Exception), () => { GetInterfaceListResponse.FromPayloadData(data.ToList().Concat(new byte[1]).ToArray()); }); - Assert.Throws(typeof(RDMMessageInvalidPDLException), () => { GetInterfaceListResponse.FromPayloadData(data.ToList().Concat(new byte[220]).ToArray()); }); +// GetInterfaceListResponse resultGetInterfaceListResponse = GetInterfaceListResponse.FromMessage(message); +// Assert.Throws(typeof(Exception), () => { GetInterfaceListResponse.FromPayloadData(data.ToList().Concat(new byte[1]).ToArray()); }); +// Assert.Throws(typeof(RDMMessageInvalidPDLException), () => { GetInterfaceListResponse.FromPayloadData(data.ToList().Concat(new byte[220]).ToArray()); }); - Assert.That(resultGetInterfaceListResponse, Is.EqualTo(getInterfaceListResponse)); +// Assert.That(resultGetInterfaceListResponse, Is.EqualTo(getInterfaceListResponse)); - var res = resultGetInterfaceListResponse.ToString(); - var src = getInterfaceListResponse.ToString(); - Assert.Multiple(() => - { - Assert.That(res, Is.Not.Null); - Assert.That(src, Is.Not.Null); - }); - Assert.That(res, Is.EqualTo(src)); - } - } -} \ No newline at end of file +// var res = resultGetInterfaceListResponse.ToString(); +// var src = getInterfaceListResponse.ToString(); +// Assert.Multiple(() => +// { +// Assert.That(res, Is.Not.Null); +// Assert.That(src, Is.Not.Null); +// }); +// Assert.That(res, Is.EqualTo(src)); +// } +// } +//} \ No newline at end of file diff --git a/RDMSharpTests/RDM/RDMMessageTest.cs b/RDMSharpTests/RDM/RDMMessageTest.cs index 5381ac4..6b1d2ea 100644 --- a/RDMSharpTests/RDM/RDMMessageTest.cs +++ b/RDMSharpTests/RDM/RDMMessageTest.cs @@ -1,132 +1,225 @@ -namespace RDMSharpTests.RDM +namespace RDMSharpTests.RDM; + +public class RDMMessageTest { - public class RDMMessageTest + [Test] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Assertion", "NUnit2010:Use EqualConstraint for better assertion messages in case of failure", Justification = "")] + public void RDMMessageParameterData_Exception() { - [Test] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Assertion", "NUnit2010:Use EqualConstraint for better assertion messages in case of failure", Justification = "")] - public void RDMMessageParameterData_Exception() - { - RDMMessage? m = new RDMMessage(); + RDMMessage? m = new RDMMessage(); - Assert.Multiple(() => - { - Assert.That(m.ParameterData, Is.Empty); - Assert.That(m.PDL, Is.EqualTo(0)); - Assert.That(m.MessageLength, Is.EqualTo(24)); - - m.ParameterData = new byte[5]; - Assert.That(m.ParameterData, Has.Length.EqualTo(5)); - Assert.That(m.PDL, Is.EqualTo(5)); - Assert.That(m.MessageLength, Is.EqualTo(29)); - - m.ParameterData = new byte[231]; - Assert.That(m.ParameterData, Has.Length.EqualTo(231)); - Assert.That(m.PDL, Is.EqualTo(231)); - Assert.That(m.MessageLength, Is.EqualTo(255)); - - Assert.Throws(() => m.ParameterData = new byte[232]); - - m = new RDMMessage - { - Parameter = ERDM_Parameter.DISC_UNIQUE_BRANCH, - Command = ERDM_Command.DISCOVERY_COMMAND, - ParameterData = new DiscUniqueBranchRequest(UID.Empty, UID.Broadcast - 1).ToPayloadData() - }; - - Assert.That(m.Equals(m), Is.True); - Assert.That(m.Equals((object)m), Is.True); - Assert.That(m.GetHashCode(), Is.EqualTo(m!.GetHashCode())); - var m2 = new RDMMessage(m.BuildMessage()); - Assert.That(m2, Is.EqualTo(m)); - Assert.That(m2.GetHashCode(), Is.EqualTo(m.GetHashCode())); - }); - } - - [Test] - public void RDMMessageLengthTest() - { - RDMMessage m = new RDMMessage - { - ParameterData = new byte[17] - }; + Assert.Multiple(() => + { + Assert.That(m.ParameterData, Is.Empty); + Assert.That(m.PDL, Is.EqualTo(0)); + Assert.That(m.MessageLength, Is.EqualTo(24)); + + m.ParameterData = new byte[5]; + Assert.That(m.ParameterData, Has.Length.EqualTo(5)); + Assert.That(m.PDL, Is.EqualTo(5)); + Assert.That(m.MessageLength, Is.EqualTo(29)); + + m.ParameterData = new byte[231]; + Assert.That(m.ParameterData, Has.Length.EqualTo(231)); + Assert.That(m.PDL, Is.EqualTo(231)); + Assert.That(m.MessageLength, Is.EqualTo(255)); + + Assert.Throws(() => m.ParameterData = new byte[232]); - Assert.Multiple(() => + m = new RDMMessage { - Assert.That(m.PDL, Is.EqualTo(17)); - Assert.That(m.MessageLength, Is.EqualTo(24 + 17)); - }); - } + Parameter = ERDM_Parameter.DISC_UNIQUE_BRANCH, + Command = ERDM_Command.DISCOVERY_COMMAND, + ParameterData = new DiscUniqueBranchRequest(UID.Empty, UID.Broadcast - 1).ToPayloadData() + }; + + Assert.That(m.Equals(m), Is.True); + Assert.That(m.Equals((object)m), Is.True); + Assert.That(m.GetHashCode(), Is.EqualTo(m!.GetHashCode())); + var m2 = new RDMMessage(m.BuildMessage()); + Assert.That(m2, Is.EqualTo(m)); + Assert.That(m2.GetHashCode(), Is.EqualTo(m.GetHashCode())); + }); + } - [Test] - public void RDMMessageChecksumTest() + [Test] + public void RDMMessageLengthTest() + { + RDMMessage m = new RDMMessage + { + ParameterData = new byte[17] + }; + + Assert.Multiple(() => + { + Assert.That(m.PDL, Is.EqualTo(17)); + Assert.That(m.MessageLength, Is.EqualTo(24 + 17)); + }); + } + + [Test] + public void RDMMessageChecksumTest() + { + //Example taken from RDM Spec + RDMMessage m = new RDMMessage { - //Example taken from RDM Spec - RDMMessage m = new RDMMessage - { - DestUID = new UID(0x1234, 0x56789abc), - SourceUID = new UID(0xcba9, 0x87654321), - PortID_or_Responsetype = 1, - Command = ERDM_Command.GET_COMMAND, - Parameter = ERDM_Parameter.STATUS_MESSAGES, - ParameterData = new byte[] { 0x04 } - }; - - Assert.That(m.Checksum, Is.EqualTo(0x66A)); - } - - [Test] - public void RDMMessageChecksumTest2() + DestUID = new UID(0x1234, 0x56789abc), + SourceUID = new UID(0xcba9, 0x87654321), + PortID_or_Responsetype = 1, + Command = ERDM_Command.GET_COMMAND, + Parameter = ERDM_Parameter.STATUS_MESSAGES, + ParameterData = new byte[] { 0x04 } + }; + + Assert.That(m.Checksum, Is.EqualTo(0x66A)); + } + + [Test] + public void RDMMessageChecksumTest2() + { + RDMMessage m = new RDMMessage { - RDMMessage m = new RDMMessage - { - DestUID = new UID(0x1234, 0x56789abc), - SourceUID = new UID(0x02B0, 0x00112233), - PortID_or_Responsetype = 1, - Command = ERDM_Command.SET_COMMAND, - Parameter = ERDM_Parameter.DMX_START_ADDRESS, - ParameterData = new byte[] { 0x00, 0x42 } - }; - - Assert.That(m.Checksum, Is.EqualTo(0x5CE)); - } - - [Test] - public void RDMMessageChecksumTest3() + DestUID = new UID(0x1234, 0x56789abc), + SourceUID = new UID(0x02B0, 0x00112233), + PortID_or_Responsetype = 1, + Command = ERDM_Command.SET_COMMAND, + Parameter = ERDM_Parameter.DMX_START_ADDRESS, + ParameterData = new byte[] { 0x00, 0x42 } + }; + + Assert.That(m.Checksum, Is.EqualTo(0x5CE)); + } + + [Test] + public void RDMMessageChecksumTest3() + { + RDMMessage m = new RDMMessage { - RDMMessage m = new RDMMessage - { - DestUID = new UID(0x1234, 0x56789abc), - SourceUID = new UID(0xcba9, 0x87654321), - PortID_or_Responsetype = 1, - Command = ERDM_Command.SET_COMMAND, - Parameter = ERDM_Parameter.DMX_START_ADDRESS, - ParameterData = Enumerable.Range(0, 200).Select(c => (byte)0xFE).ToArray() - }; - - Assert.That(m.Checksum, Is.EqualTo(0xCF34)); - } - - [Test] - public void RDMMessageDiscoveryBuildMessage() + DestUID = new UID(0x1234, 0x56789abc), + SourceUID = new UID(0xcba9, 0x87654321), + PortID_or_Responsetype = 1, + Command = ERDM_Command.SET_COMMAND, + Parameter = ERDM_Parameter.DMX_START_ADDRESS, + ParameterData = Enumerable.Range(0, 200).Select(c => (byte)0xFE).ToArray() + }; + + Assert.That(m.Checksum, Is.EqualTo(0xCF34)); + } + + [Test] + public void RDMMessageDiscoveryBuildMessage() + { + RDMMessage m = new RDMMessage { - RDMMessage m = new RDMMessage - { - DestUID = new UID(0x1234, 0x56789abc), - SourceUID = new UID(0x02B0, 0x00112233), - Command = ERDM_Command.DISCOVERY_COMMAND, - Parameter = ERDM_Parameter.DISC_MUTE - }; + DestUID = new UID(0x1234, 0x56789abc), + SourceUID = new UID(0x02B0, 0x00112233), + Command = ERDM_Command.DISCOVERY_COMMAND, + Parameter = ERDM_Parameter.DISC_MUTE + }; - byte[] erg = m.BuildMessage(); + byte[] erg = m.BuildMessage(); - byte[] expected = new byte[] - { - 0xcc, 0x01, 0x18, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0x02, 0xb0, 0x00, 0x11, - 0x22, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x04, 0x79 - }; + byte[] expected = new byte[] + { + 0xcc, 0x01, 0x18, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0x02, 0xb0, 0x00, 0x11, + 0x22, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x04, 0x79 + }; - Assert.That(erg.SequenceEqual(expected), Is.True); - } + Assert.That(erg.SequenceEqual(expected), Is.True); + } + + + [Test] + public void RDMMessageNACKBuildMessage() + { + RDMMessage m = new RDMMessage(ERDM_NackReason.DATA_OUT_OF_RANGE) + { + DestUID = new UID(0x1234, 0x56789abc), + SourceUID = new UID(0x02B0, 0x00112233), + Command = ERDM_Command.GET_COMMAND_RESPONSE, + Parameter = ERDM_Parameter.ENDPOINT_TO_UNIVERSE, + }; + + + byte[] erg = m.BuildMessage(); + + byte[] expected = new byte[] + { + 0xcc, 0x01, 0x1a, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0x02, 0xb0, 0x00, 0x11, + 0x22, 0x33, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x09, 0x03, 0x02, 0x00, 0x06, + 0x04, 0xa0 + }; + + RDMMessage m2 = new RDMMessage(erg); + + Assert.That(m2.ResponseType, Is.EqualTo(m.ResponseType)); + Assert.That(m2.NackReason, Is.EqualTo(m.NackReason)); + Assert.That(m2.PDL, Is.EqualTo(m.PDL)); + Assert.That(m2.Command, Is.EqualTo(m.Command)); + Assert.That(erg, Is.EqualTo(expected)); + } + + + + [Test] + public void RDMMessageAckBuildMessage() + { + var ackTimer = new AcknowledgeTimer(TimeSpan.FromMilliseconds(5000)); + RDMMessage m = new RDMMessage(ackTimer) + { + DestUID = new UID(0x1234, 0x56789abc), + SourceUID = new UID(0x02B0, 0x00112233), + Command = ERDM_Command.GET_COMMAND_RESPONSE, + Parameter = ERDM_Parameter.LAMP_STATE, + }; + + + byte[] erg = m.BuildMessage(); + + byte[] expected = new byte[] + { + 0xcc, 0x01, 0x1a, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0x02, 0xb0, 0x00, 0x11, + 0x22, 0x33, 0x00, 0x01, 0x00, 0x00, 0x00, 0x21, 0x04, 0x03, 0x02, 0x00, 0x32, + 0x04, 0xc6 + }; + + RDMMessage m2 = new RDMMessage(erg); + + Assert.That(m2.ResponseType, Is.EqualTo(m.ResponseType)); + Assert.That(m2.AcknowledgeTimer, Is.EqualTo(ackTimer)); + Assert.That(m2.PDL, Is.EqualTo(m.PDL)); + Assert.That(m2.Command, Is.EqualTo(m.Command)); + Assert.That(erg, Is.EqualTo(expected)); + } + [Test] + public void RDMMessageAckHighResBuildMessage() + { + var ackTimer = new AcknowledgeTimerHighRes(TimeSpan.FromMilliseconds(520)); + RDMMessage m = new RDMMessage(ackTimer) + { + DestUID = new UID(0x1234, 0x56789abc), + SourceUID = new UID(0x02B0, 0x00112233), + Command = ERDM_Command.GET_COMMAND_RESPONSE, + Parameter = ERDM_Parameter.LAMP_STATE, + }; + + + byte[] erg = m.BuildMessage(); + + byte[] expected = new byte[] + { + 0xcc, 0x01, 0x1a, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0x02, 0xb0, 0x00, 0x11, + 0x22, 0x33, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x04, 0x03, 0x02, 0x02, 0x08, + 0x04, 0xa1 + }; + + RDMMessage m2 = new RDMMessage(erg); + + Assert.That(m2.ResponseType, Is.EqualTo(m.ResponseType)); + Assert.That(m2.AcknowledgeTimer, Is.EqualTo(ackTimer)); + Assert.That(m2.PDL, Is.EqualTo(m.PDL)); + Assert.That(m2.Command, Is.EqualTo(m.Command)); + Assert.That(erg, Is.EqualTo(expected)); } } diff --git a/RDMSharpTests/RDMSharpTests.csproj b/RDMSharpTests/RDMSharpTests.csproj index 7135d0a..ee7848b 100644 --- a/RDMSharpTests/RDMSharpTests.csproj +++ b/RDMSharpTests/RDMSharpTests.csproj @@ -1,7 +1,7 @@  - net6.0;net7.0;net8.0;net9.0 + net7.0;net8.0;net9.0;net10.0 enable enable diff --git a/README.md b/README.md index 1217155..76b8a01 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ RDMSharp is a C# library that abstracts the communication using Remote Device Ma - **Device discovery** and management - **Support for all major RDM commands** - **Extensible architecture** for custom device types and parameters -- **Cross-platform**: Works on .NET 6, .NET 7, .NET 8, .NET 9 and in future upcomming versions +- **Cross-platform**: Works on .NET 6, .NET 7, .NET 8, .NET 9, .NET 10 and in future upcomming versions - **Comprehensive error handling** and logging - **Unit tested** for reliability @@ -37,7 +37,7 @@ Or via the NuGet Package Manager in Visual Studio. - [![.NET 7](https://img.shields.io/badge/.NET%207-5C2D91?logo=.net&logoColor=white)](https://dotnet.microsoft.com/download/dotnet/7.0) (not recommended) - [![.NET 8](https://img.shields.io/badge/.NET%208-5C2D91?logo=.net&logoColor=white)](https://dotnet.microsoft.com/download/dotnet/8.0) - [![.NET 9](https://img.shields.io/badge/.NET%209-5C2D91?logo=.net&logoColor=white)](https://dotnet.microsoft.com/download/dotnet/9.0) -- [![.NET 10](https://img.shields.io/badge/.NET%2010-5C2D91?logo=.net&logoColor=white)](https://dotnet.microsoft.com/download/dotnet/10.0) (upcoming) +- [![.NET 10](https://img.shields.io/badge/.NET%2010-5C2D91?logo=.net&logoColor=white)](https://dotnet.microsoft.com/download/dotnet/10.0) ## Contributing