Skip to content

Commit

Permalink
Merge pull request #149 from iCsysAS/master
Browse files Browse the repository at this point in the history
Add new types and make extensionobject encoding/decoding extendable
  • Loading branch information
nauful authored Mar 2, 2024
2 parents 0f53bfa + debb00d commit 9e06717
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 73 deletions.
2 changes: 1 addition & 1 deletion NET Core/LibUA/LibUA.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<PackageId>nauful-$(AssemblyName)-core</PackageId>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageProjectUrl>https://github.com/nauful/libua</PackageProjectUrl>
Expand Down
74 changes: 3 additions & 71 deletions NET Core/LibUA/MemoryBufferExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1665,90 +1665,22 @@ public static bool Decode(this MemoryBuffer mem, out ExtensionObject obj)
if (!mem.DecodeUAByteString(out byte[] str)) { return false; }
obj.Body = str;

var tmp = new MemoryBuffer(str);
return obj.TryDecodeByteString();

switch (obj.TypeId.NumericIdentifier)
{
case (uint)UAConst.ObjectAttributes_Encoding_DefaultBinary:
ObjectAttributes oa;
if (!tmp.Decode(out oa)) { return false; }
obj.Payload = oa;
break;
case (uint)UAConst.ObjectTypeAttributes_Encoding_DefaultBinary:
ObjectTypeAttributes ota;
if (!tmp.Decode(out ota)) { return false; }
obj.Payload = ota;
break;
case (uint)UAConst.VariableAttributes_Encoding_DefaultBinary:
VariableAttributes va;
if (!tmp.Decode(out va)) { return false; }
obj.Payload = va;
break;
case (uint)UAConst.VariableTypeAttributes_Encoding_DefaultBinary:
VariableTypeAttributes vta;
if (!tmp.Decode(out vta)) { return false; }
obj.Payload = vta;
break;
case (uint)UAConst.Argument_Encoding_DefaultBinary:
Argument arg;
if (!tmp.Decode(out arg)) { return false; }
obj.Payload = arg;
break;
default:
break;
}

return true;

}

return true;
}

public static bool Encode(this MemoryBuffer mem, ExtensionObject obj)
{
if (obj == null)
if (obj == null || !obj.TryEncodeByteString(mem.Capacity))
{
if (!mem.Encode(NodeId.Zero)) { return false; }
return mem.Encode((byte)ExtensionObjectBodyType.None);
}

if (obj.Payload != null)
{
var tmp = new MemoryBuffer(mem.Capacity);
UAConst payloadType = 0;
switch (obj.Payload)
{
case ObjectAttributes oa:
payloadType = UAConst.ObjectAttributes_Encoding_DefaultBinary;
if (!tmp.Encode(oa)) { return false; }
break;
case ObjectTypeAttributes ota:
payloadType = UAConst.ObjectTypeAttributes_Encoding_DefaultBinary;
if (!tmp.Encode(ota)) { return false; }
break;
case VariableAttributes va:
payloadType = UAConst.VariableAttributes_Encoding_DefaultBinary;
if (!tmp.Encode(va)) { return false; }
break;
case VariableTypeAttributes vta:
payloadType = UAConst.VariableTypeAttributes_Encoding_DefaultBinary;
if (!tmp.Encode(vta)) { return false; }
break;
case Argument arg:
payloadType = UAConst.Argument_Encoding_DefaultBinary;
if (!tmp.Encode(arg)) { return false; }
break;
default:
break;
}
if (payloadType != 0)
{
obj.TypeId = new NodeId(payloadType);
obj.Body = new byte[tmp.Position];
Array.Copy(tmp.Buffer, obj.Body, obj.Body.Length);
}
}

if (!mem.Encode(obj.TypeId)) { return false; }

if (obj.Body == null)
Expand Down
155 changes: 154 additions & 1 deletion NET Core/LibUA/Types.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using LibUA.ValueTypes;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -5800,10 +5801,162 @@ public override string ToString()

public class ExtensionObject
{
private static ConcurrentDictionary<Type, Func<MemoryBuffer, NodeId>> _objectEncoders = new();
private static ConcurrentDictionary<NodeId, Func<MemoryBuffer, object>> _objectDecoders = new();
public static void RegisterEncoder<TObject>(Func<MemoryBuffer,NodeId> encoder)
{
_objectEncoders[typeof(TObject)] = encoder;
}

public static void RegisterDecoder<TObject>(NodeId TypeId, Func<MemoryBuffer, TObject> decoder) where TObject : class
{
_objectDecoders[TypeId] = decoder;
}



public NodeId TypeId { get; set; }
public byte[] Body { get; set; }

public object Payload { get; set; }

public bool TryEncodeByteString(int BufferCapacity)
{
TypeId = null;
if (Payload != null)
{
var buffer = new MemoryBuffer(BufferCapacity);
UAConst payloadType = 0;

if(_objectEncoders.TryGetValue(Payload.GetType(), out var encoder))
{
TypeId = encoder(buffer);
if (TypeId == null)
return false;
}
else
{
switch (Payload)
{
case ObjectAttributes oa:
payloadType = UAConst.ObjectAttributes_Encoding_DefaultBinary;
if (!buffer.Encode(oa)) { return false; }
break;
case ObjectTypeAttributes ota:
payloadType = UAConst.ObjectTypeAttributes_Encoding_DefaultBinary;
if (!buffer.Encode(ota)) { return false; }
break;
case VariableAttributes va:
payloadType = UAConst.VariableAttributes_Encoding_DefaultBinary;
if (!buffer.Encode(va)) { return false; }
break;
case VariableTypeAttributes vta:
payloadType = UAConst.VariableTypeAttributes_Encoding_DefaultBinary;
if (!buffer.Encode(vta)) { return false; }
break;
case Argument arg:
payloadType = UAConst.Argument_Encoding_DefaultBinary;
if (!buffer.Encode(arg)) { return false; }
break;
case EUInformation eui:
payloadType = UAConst.EUInformation;
if(!buffer.Encode(eui)) { return false; }
break;
case OpcRange range:
payloadType = UAConst.Range;
if(!buffer.Encode(range)) { return false; }
break;
default:
break;
}

if (payloadType != 0)
{
TypeId = new NodeId(payloadType);
}
}

if(TypeId != null)
{
Body = new byte[buffer.Position];
Array.Copy(buffer.Buffer, Body, Body.Length);
return true;
}

return false;
}

return false;
}

public bool TryDecodeByteString()
{
var tmp = new MemoryBuffer(Body);

if(_objectDecoders.TryGetValue(TypeId, out var decoder))
{
Payload = decoder(tmp);
if (Payload != null)
return true;
}

switch (TypeId.NumericIdentifier)
{
case (uint)UAConst.ObjectAttributes_Encoding_DefaultBinary:
ObjectAttributes oa;
if (!tmp.Decode(out oa)) { return false; }
Payload = oa;
break;
case (uint)UAConst.ObjectTypeAttributes_Encoding_DefaultBinary:
ObjectTypeAttributes ota;
if (!tmp.Decode(out ota)) { return false; }
Payload = ota;
break;
case (uint)UAConst.VariableAttributes_Encoding_DefaultBinary:
VariableAttributes va;
if (!tmp.Decode(out va)) { return false; }
Payload = va;
break;
case (uint)UAConst.VariableTypeAttributes_Encoding_DefaultBinary:
VariableTypeAttributes vta;
if (!tmp.Decode(out vta)) { return false; }
Payload = vta;
break;
case (uint)UAConst.Argument_Encoding_DefaultBinary:
Argument arg;
if (!tmp.Decode(out arg)) { return false; }
Payload = arg;
break;
case (uint)UAConst.EUInformation:
EUInformation eui;
if(!tmp.Decode(out eui)) { return false; }
Payload = eui;
break;
case (uint)UAConst.Range:
OpcRange range;
if(!tmp.Decode(out range)) { return false; }
Payload = range;
break;
default:
break;
}

return Payload != null;
}
}

public class ExtensionObject<TPayload> : ExtensionObject
{
public TPayload Value
{
get
{
if (Payload != null && Payload is TPayload tPayload)
return tPayload;
return default;
}
set => Payload = value;
}
}

public class DataValue
Expand Down
64 changes: 64 additions & 0 deletions NET Core/LibUA/ValueTypes/EUInformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using LibUA.Core;
using System;

namespace LibUA.ValueTypes;

public class EUInformation
{
public string NameSpaceUri { get; set; } = "http://www.opcfoundation.org/UA/units/un/cefact";
public int UnitId { get; set; } = -1;
public LocalizedText DisplayName { get; set; } = new("");
public LocalizedText Description { get; set; } = new("");
}

public static class EUInformationExtensions
{
public static int CodingSize(this MemoryBuffer mem, EUInformation dv)
{
int sum = 0;

sum += mem.CodingSizeUAString(dv.NameSpaceUri);
sum += mem.CodingSize(dv.UnitId);
sum += mem.CodingSize(dv.DisplayName);
sum += mem.CodingSize(dv.Description);

return sum;
}

public static bool Encode(this MemoryBuffer mem, EUInformation item)
{
if (!mem.EncodeUAString(item.NameSpaceUri)) { return false; }
if (!mem.Encode(item.UnitId)) { return false; }
if (!mem.Encode(item.DisplayName)) { return false; }
if (!mem.Encode(item.Description)) { return false; }

return true;
}

public static bool Decode(this MemoryBuffer mem, out EUInformation wv)
{
wv = null;

if (!mem.DecodeUAString(out string namespaceUri)) { return false; }
if (!mem.Decode(out int unitId)) { return false; }
if (!mem.Decode(out LocalizedText displayName)) { return false; }
if (!mem.Decode(out LocalizedText description)) { return false; }

try
{
wv = new EUInformation()
{
NameSpaceUri = namespaceUri,
UnitId = unitId,
DisplayName = displayName,
Description = description
};
}
catch
{
return false;
}

return true;
}
}
53 changes: 53 additions & 0 deletions NET Core/LibUA/ValueTypes/OpcRange.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using LibUA.Core;

namespace LibUA.ValueTypes;

public class OpcRange
{
public double High { get; set; }
public double Low { get; set; }
}

public static class RangeExtensions
{
public static int CodingSize(this MemoryBuffer mem, OpcRange dv)
{
int sum = 0;

sum += mem.CodingSize(dv.Low);
sum += mem.CodingSize(dv.High);

return sum;
}

public static bool Encode(this MemoryBuffer mem, OpcRange item)
{
if (!mem.Encode(item.Low)) { return false; }
if (!mem.Encode(item.High)) { return false; }

return true;
}

public static bool Decode(this MemoryBuffer mem, out OpcRange wv)
{
wv = null;

if (!mem.Decode(out double low)) { return false; }
if (!mem.Decode(out double high)) { return false; }

try
{
wv = new OpcRange()
{
High = high,
Low = low
};
}
catch
{
return false;
}

return true;
}
}

0 comments on commit 9e06717

Please sign in to comment.