Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 125 additions & 43 deletions NodeSetToAML.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3113,6 +3113,8 @@ private void AddAttributeData( AttributeFamilyType attribute, UANode uaNode )

AddEnumerationFieldDefinition( attribute, uaNode );

AddOptionSetFieldDefintion( attribute, uaNode );

AttributeType nodeIdAttribute = AddModifyAttribute( attribute.Attribute,"NodeId", "NodeId",
new Variant( uaNode.DecodedNodeId ) );

Expand Down Expand Up @@ -3211,32 +3213,16 @@ private void AddStructureFieldDefinition( AttributeFamilyType attribute, UANode
RemoveUnwantedAttribute( structureFieldAttribute, "MaxStringLength" );
}

if (field.Description != null && field.Description.Length > 0)
{
List<Variant> localizedTextList = new List<Variant>(field.Description.Length);
foreach(NodeSet.LocalizedText description in field.Description)
{
localizedTextList.Add(
new Variant(
new LocalizedText(description.Locale, description.Value)));
}
Variant localizedTextArray = new Variant(localizedTextList);
AttributeType descriptionCreated = AddLocalizedTextArrayAttribute(
structureFieldAttribute,
"Description",
field.Description);

LocalizedText localizedText = new LocalizedText(
field.Description[0].Locale, field.Description[0].Value);
AddModifyAttribute(structureFieldAttribute.Attribute,
"Description", "LocalizedText", localizedTextArray,
bListOf: true);
RemoveUnwantedAttribute(structureFieldAttribute.Attribute["Description"],
"StructureFieldDefinition");
}
else if (structureFieldAttribute.Attribute["Description"] != null)
if (descriptionCreated != null)
{
RemoveUnwantedAttribute(structureFieldAttribute, "Description");
RemoveUnwantedAttribute(descriptionCreated,"StructureFieldDefinition");
}



// Remove the NodeId from the structure Field
AttributeType nodeIdAttribute = structureFieldAttribute.Attribute[ "DataType" ];
if( nodeIdAttribute != null )
Expand Down Expand Up @@ -3297,8 +3283,27 @@ private void AddEnumerationFieldDefinition(AttributeFamilyType attribute, UANode
enumValues.DecodedValue, bListOf: true);
if (added != null)
{
// Remove empty values
RemoveNodeIdsFromDefinition(added);

foreach( AttributeType arrayElement in added.Attribute )
{
List<string> toBeRemoved = new List<string>();

foreach ( AttributeType parameter in arrayElement.Attribute )
{
if ( string.IsNullOrEmpty( parameter.Value ) )
{
toBeRemoved.Add(parameter.Name);
}
}

foreach (string removeAttribute in toBeRemoved)
{
RemoveUnwantedAttribute(arrayElement, removeAttribute);
}
}

AttributeType nodeIdAttribute = AddModifyAttribute(added.Attribute,
"NodeId", "NodeId", new Variant(EnumValuesPropertyId));

Expand Down Expand Up @@ -3327,30 +3332,14 @@ private void AddEnumerationFieldDefinition(AttributeFamilyType attribute, UANode
fieldAttribute.RecreateAttributeInstance(enumFieldSource);
fieldAttribute.Name = fieldDefinition.Name;

AddModifyAttribute(fieldAttribute.Attribute,
"Name", "String", new Variant(fieldDefinition.Name));
// Remove the Name
RemoveUnwantedAttribute(fieldAttribute, "Name");

LocalizedText descriptionLocalizedText = new LocalizedText("");
// Description is an array of LocalizedText

if (fieldDefinition.Description != null && fieldDefinition.Description.Length > 0)
{
descriptionLocalizedText = new LocalizedText(
fieldDefinition.Description[0].Locale, fieldDefinition.Description[0].Value);
}
AddLocalizedTextArrayAttribute(fieldAttribute, "Description", fieldDefinition.Description);

AddModifyAttribute(fieldAttribute.Attribute, "Description", "LocalizedText",
new Variant(descriptionLocalizedText));

LocalizedText displayNameLocalizedText = new LocalizedText("");

if (fieldDefinition.DisplayName != null && fieldDefinition.DisplayName.Length > 0)
{
displayNameLocalizedText = new LocalizedText(
fieldDefinition.DisplayName[0].Locale, fieldDefinition.DisplayName[0].Value);
}

AddModifyAttribute(fieldAttribute.Attribute, "DisplayName", "LocalizedText",
new Variant(displayNameLocalizedText));
AddLocalizedTextArrayAttribute( fieldAttribute, "DisplayName", fieldDefinition.DisplayName);

AddModifyAttribute(fieldAttribute.Attribute,
"Value", "Int32", new Variant(fieldDefinition.Value));
Expand All @@ -3366,6 +3355,56 @@ private void AddEnumerationFieldDefinition(AttributeFamilyType attribute, UANode
}
}

private void AddOptionSetFieldDefintion( AttributeFamilyType attribute, UANode uaNode )
{
UADataType optionSetNode = uaNode as UADataType;
if (optionSetNode != null &&
optionSetNode.Definition != null &&
optionSetNode.Definition.IsOptionSet == true)
{
if ( optionSetNode.Definition.Field != null &&
optionSetNode.Definition.Field.Length > 0 )
{
string path = BuildLibraryReference(ATLPrefix, Opc.Ua.Namespaces.OpcUa, "ListOfOptionSet");
AttributeFamilyType optionSetFieldDefinition = m_cAEXDocument.FindByPath(path) as AttributeFamilyType;

AttributeType optionSetFields = new AttributeType(
new System.Xml.Linq.XElement(defaultNS + "Attribute"));

optionSetFields.RecreateAttributeInstance(optionSetFieldDefinition as AttributeFamilyType);
optionSetFields.Name = "OptionSetFieldDefinition";
optionSetFields.AdditionalInformation.Append(OpcUaTypeOnly);

string optionSetPath = BuildLibraryReference(ATLPrefix, Opc.Ua.Namespaces.OpcUa, "OptionSet");
AttributeFamilyType optionSetSource = m_cAEXDocument.FindByPath(optionSetPath) as AttributeFamilyType;

foreach (DataTypeField fieldDefinition in optionSetNode.Definition.Field)
{
AttributeType fieldAttribute = new AttributeType(new System.Xml.Linq.XElement(defaultNS + "Attribute"));

fieldAttribute.RecreateAttributeInstance(optionSetSource);
fieldAttribute.Name = fieldDefinition.Name;

AttributeType valueAttribute = AddModifyAttribute(fieldAttribute.Attribute,
"Value", "Int32", new Variant(fieldDefinition.Value));

RemoveUnwantedAttribute(valueAttribute, "NodeId");
RemoveUnwantedAttribute(fieldAttribute, "ValidBits");
RemoveUnwantedAttribute(fieldAttribute, "NodeId");

optionSetFields.Attribute.Insert(fieldAttribute, false, true);
}

attribute.Attribute.Insert(optionSetFields, false, true);
}
else
{
bool unexpected = true;
}
}
}


private AttributeFamilyType ProcessDataType(NodeSet.UANode node)
{
var typeNode = node as MarkdownProcessor.NodeSet.UADataType;
Expand Down Expand Up @@ -3400,6 +3439,49 @@ private AttributeFamilyType ProcessDataType(NodeSet.UANode node)

return added;
}

private AttributeType AddLocalizedTextArrayAttribute( AttributeType attribute,
string name, NodeSet.LocalizedText[] texts)
{
AttributeType created = null;

// Currently for Field Definitions
Variant localizedTextArray = LocalizedTextArrayAsVariant(texts);
if (localizedTextArray.TypeInfo != null &&
localizedTextArray.TypeInfo.BuiltInType != null &&
localizedTextArray.TypeInfo.BuiltInType == BuiltInType.Variant)
{
created = AddModifyAttribute(attribute.Attribute, name, "LocalizedText",
localizedTextArray, bListOf: true);
}
else
{
RemoveUnwantedAttribute(attribute, name);
}

return created;
}

private Variant LocalizedTextArrayAsVariant(NodeSet.LocalizedText[] array )
{
Variant localizedTextArray = new Variant();

if (array != null && array.Length >= 0)
{
List<Variant> localizedTextList = new List<Variant>(array.Length);
foreach (NodeSet.LocalizedText text in array)
{
localizedTextList.Add(
new Variant(
new LocalizedText(text.Locale, text.Value)));
}

localizedTextArray = new Variant(localizedTextList);
}

return localizedTextArray;
}

#endregion

#region INSTANCE
Expand Down
118 changes: 116 additions & 2 deletions SystemTest/NodeSetFiles/TestAml.xml
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,120 @@
</Definition>
</UADataType>

<UADataType NodeId="ns=1;i=3008" BrowseName="Test_Duplex">
<DisplayName>Duplex</DisplayName>
<Category>BNM Ethernet Base Info</Category>
<Documentation>https://reference.opcfoundation.org/v105/Core/docs/Part22/5.3.1/#5.3.1.1</Documentation>
<References>
<Reference ReferenceType="HasProperty" BrowseName="EnumValues">ns=1;i=6238</Reference>
<Reference ReferenceType="HasSubtype" IsForward="false" BrowseName="Enumeration">i=29</Reference>
</References>
<Definition Name="Duplex">
<Field Name="Full" Value="0">
<Description Locale="en">Full duplex.</Description>
</Field>
<Field Name="Half" Value="1">
<Description>Half duplex.</Description>
</Field>
<Field Name="Unknown" Value="2">
</Field>
</Definition>
</UADataType>
<UAVariable NodeId="ns=1;i=6238" BrowseName="EnumValues" ParentNodeId="i=24210" DataType="i=7594" ValueRank="1" ArrayDimensions="3">
<DisplayName>EnumValues</DisplayName>
<References>
<Reference ReferenceType="HasTypeDefinition" BrowseName="PropertyType">i=68</Reference>
<Reference ReferenceType="HasProperty" IsForward="false" BrowseName="Duplex">i=24210</Reference>
</References>
<Value>
<ListOfExtensionObject xmlns="http://opcfoundation.org/UA/2008/02/Types.xsd">
<ExtensionObject>
<TypeId>
<Identifier>i=7616</Identifier>
</TypeId>
<Body>
<EnumValueType>
<Value>0</Value>
<DisplayName>
<Locale>de</Locale>
<Text>Voll</Text>
</DisplayName>
<Description>
<Locale>de</Locale>
<Text>Vollduplex</Text>
</Description>
</EnumValueType>
</Body>
</ExtensionObject>
<ExtensionObject>
<TypeId>
<Identifier>i=7616</Identifier>
</TypeId>
<Body>
<EnumValueType>
<Value>1</Value>
<DisplayName>
<Text>Half</Text>
</DisplayName>
<Description>
<Text>Half duplex.</Text>
</Description>
</EnumValueType>
</Body>
</ExtensionObject>
<ExtensionObject>
<TypeId>
<Identifier>i=7616</Identifier>
</TypeId>
<Body>
<EnumValueType>
<Value>2</Value>
<!-- It's not valid that an enumvaluetype doesn't have a name, this is just for testing purposes-->
</EnumValueType>
</Body>
</ExtensionObject>
</ListOfExtensionObject>
</Value>
</UAVariable>



<UADataType NodeId="ns=1;i=3009" BrowseName="TestAlarmMask">
<DisplayName>AlarmMask</DisplayName>
<Category>A &amp; C Summary</Category>
<Documentation>https://reference.opcfoundation.org/v105/Core/docs/Part9/8.3</Documentation>
<References>
<Reference ReferenceType="HasProperty" BrowseName="OptionSetValues">ns=1;i=6239</Reference>
<Reference ReferenceType="HasSubtype" IsForward="false" BrowseName="UInt16">i=5</Reference>
</References>
<Definition Name="AlarmMask" IsOptionSet="true">
<Field Name="Active" Value="0" />
<Field Name="Unacknowledged" Value="1" />
<Field Name="Unconfirmed" Value="2" />
</Definition>
</UADataType>
<UAVariable NodeId="ns=1;i=6239" BrowseName="OptionSetValues" ParentNodeId="i=32251" DataType="LocalizedText" ValueRank="1" ArrayDimensions="3">
<DisplayName>OptionSetValues</DisplayName>
<References>
<Reference ReferenceType="HasTypeDefinition" BrowseName="PropertyType">i=68</Reference>
<Reference ReferenceType="HasProperty" IsForward="false" BrowseName="AlarmMask">i=32251</Reference>
</References>
<Value>
<ListOfLocalizedText xmlns="http://opcfoundation.org/UA/2008/02/Types.xsd">
<LocalizedText>
<Text>Active</Text>
</LocalizedText>
<LocalizedText>
<Text>Unacknowledged</Text>
</LocalizedText>
<LocalizedText>
<Text>Unconfirmed</Text>
</LocalizedText>
</ListOfLocalizedText>
</Value>
</UAVariable>


<UAObject SymbolicName="http___opcfoundation_org_UA_FX_AML_TESTING" NodeId="ns=1;i=5000" BrowseName="1:http://opcfoundation.org/UA/FX/AML/TESTING" ParentNodeId="i=11715">
<DisplayName>http://opcfoundation.org/UA/FX/AML/TESTING</DisplayName>
<References>
Expand Down Expand Up @@ -3586,8 +3700,8 @@
<!-- Next Numbers
ObjectType 1009
VariableType 2006
DataType 3008
DataType 3010
Object 5025
Variable 6238
Variable 6240
-->
</UANodeSet>
22 changes: 18 additions & 4 deletions SystemTest/TestEnums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,6 @@ public void TestFieldDefinition(uint nodeId, object enumObject)

foreach (AttributeType fieldDefinition in enumFieldDefinition.Attribute)
{
AttributeType nameAttribute = fieldDefinition.Attribute["Name"];
Assert.IsNotNull(nameAttribute, "Field Definition Name is null");
Assert.IsNotNull(nameAttribute.Value, "Field Definition Name Value is null");
Assert.AreEqual(fieldDefinition.Name, nameAttribute.Value, "Field Definition Name does not match Attribute Name");
AttributeType valueAttribute = fieldDefinition.Attribute["Value"];
Assert.IsNotNull(valueAttribute, "Field Definition Value is null");
Assert.IsNotNull(valueAttribute.Value, "Field Definition Value-Value is null");
Expand Down Expand Up @@ -457,6 +453,24 @@ public void TestUnwantedAttribute(AttributeType attribute, string unwantedAttrib
}
}

[TestMethod, Timeout(TestHelper.UnitTestTimeout)]
public void TestForRemovedAttributes()
{
AttributeFamilyType objectToTest = GetTestAttribute("3008", foundation: false);

AttributeType enumFieldDefinition = GetAttribute(objectToTest, "EnumFieldDefinition");
AttributeType unknownElement = GetAttribute(enumFieldDefinition, "Unknown");
Assert.IsNull(unknownElement.Attribute["DisplayName"]);
Assert.IsNull(unknownElement.Attribute["Description"]);

AttributeType enumValues = GetAttribute(objectToTest, "EnumValues");
AttributeType lastArrayElement = GetAttribute(enumValues, "2");
Assert.IsNull(lastArrayElement.Attribute["DisplayName"]);
Assert.IsNull(lastArrayElement.Attribute["Description"]);
}



#endregion

#region Helpers
Expand Down
Loading