Files
lmxopcua/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Ab.Transport/Logix/LogixServices.cs
T

40 lines
1.9 KiB
C#

using ZB.MOM.WW.OtOpcUa.Driver.Ab.Transport.Cip;
using ZB.MOM.WW.OtOpcUa.Driver.Ab.Transport.Wire;
namespace ZB.MOM.WW.OtOpcUa.Driver.Ab.Transport.Logix;
/// <summary>Logix Read/Write Tag (plain and fragmented) builders and the read-reply parser.</summary>
public static class LogixServices
{
private static CipWriter Start(byte service, ReadOnlySpan<byte> path) =>
new CipWriter().U8(service).U8((byte)(path.Length / 2)).Bytes(path);
public static byte[] ReadTag(ReadOnlySpan<byte> path, ushort elements) => Start(0x4C, path).U16(elements).ToArray();
public static byte[] ReadTagFragmented(ReadOnlySpan<byte> path, ushort elements, uint offset) =>
Start(0x52, path).U16(elements).U32(offset).ToArray();
public static byte[] WriteTag(ReadOnlySpan<byte> path, ushort type, ushort? handle, ushort elements, ReadOnlySpan<byte> data)
{
var w = Start(0x4D, path).U16(type);
if (type == LogixTypeCode.Struct) w.U16(handle ?? throw new ArgumentException("Struct write needs a handle."));
return w.U16(elements).Bytes(data).ToArray();
}
public static byte[] WriteTagFragmented(ReadOnlySpan<byte> path, ushort type, ushort? handle, ushort elements, uint offset, ReadOnlySpan<byte> data)
{
var w = Start(0x53, path).U16(type);
if (type == LogixTypeCode.Struct) w.U16(handle ?? throw new ArgumentException("Struct write needs a handle."));
return w.U16(elements).U32(offset).Bytes(data).ToArray();
}
public static (ushort TypeCode, ushort? StructHandle, ReadOnlyMemory<byte> Data) ParseReadReply(CipReply reply)
{
if (reply.GeneralStatus is not (0x00 or 0x06))
throw new AbTransportException(reply.Status, $"Read failed: general 0x{reply.GeneralStatus:X2}.");
var r = new CipReader(reply.Data.Span);
var type = r.U16();
ushort? handle = type == LogixTypeCode.Struct ? r.U16() : null;
return (type, handle, reply.Data[r.Position..]);
}
}