From 027fbafc27b7f6c54b7ef669c910d80c43788a90 Mon Sep 17 00:00:00 2001 From: timyhac Date: Sun, 23 Jun 2024 09:44:47 +1000 Subject: [PATCH] Add the TagDynamic example --- .../CSharp DotNetCore/ExampleTagDynamic.cs | 228 ++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 src/Examples/CSharp DotNetCore/ExampleTagDynamic.cs diff --git a/src/Examples/CSharp DotNetCore/ExampleTagDynamic.cs b/src/Examples/CSharp DotNetCore/ExampleTagDynamic.cs new file mode 100644 index 00000000..f51328b8 --- /dev/null +++ b/src/Examples/CSharp DotNetCore/ExampleTagDynamic.cs @@ -0,0 +1,228 @@ +using libplctag; +using System; + +namespace CSharp_DotNetCore +{ + class ExampleTagDynamic + { + public static void Run() + { + + /* + * + * WARNING: THIS HAS NOT BEEN TESTED + * + */ + + var tag = new TagDynamic() + { + Name = "MyDintTag", + // Configure other properties.... + }; + + tag.Initialize(); // Detects the tag is a DINT and configures the appropriate getter and setter. + Console.WriteLine(tag.Value); // Prints e.g. 1234 + tag.Value = 4321; + tag.Write(); + tag.Value = "Hello world"; // This will compile but will fail at runtime + } + + class TagDynamic + { + private readonly Tag _tag; + private Func decoder; + private Action encoder; + + public TagDynamic() + { + _tag = new Tag() + { + PlcType = libplctag.PlcType.ControlLogix, // Only certain types of devices support this, so hard-code this + Protocol = Protocol.ab_eip, // Only certain types of devices support this, so hard-code this + }; + + _tag.ReadCompleted += (s, e) => ReadCompleted?.Invoke(this, e); + _tag.WriteCompleted += (s, e) => WriteCompleted?.Invoke(this, e); + } + + /// + public void Initialize() + { + _tag.Initialize(); + + // After we have read the tag metadata, configure the encoder/decoder + Configure(); + } + + /// + public void Write() + { + if (!_tag.IsInitialized) + { + Initialize(); + } + + _tag.Write(); + } + + /// + public void Read() + { + if (!_tag.IsInitialized) + { + Initialize(); + return; // Initialize already does a read, so in this case we don't need to read again and can return early. + } + + _tag.Read(); + } + + /// + /// The value stored in local memory. + /// + public object Value + { + get => decoder(_tag, 0); + set => encoder(_tag, 0, value); + } + + /// + public string Gateway + { + get => _tag.Gateway; + set => _tag.Gateway = value; + } + + /// + public string Path + { + get => _tag.Path; + set => _tag.Path = value; + } + + /// + public string Name + { + get => _tag.Name; + set => _tag.Name = value; + } + + /// + public TimeSpan Timeout + { + get => _tag.Timeout; + set => _tag.Timeout = value; + } + + /// + public TimeSpan? AutoSyncReadInterval + { + get => _tag.AutoSyncReadInterval; + set => _tag.AutoSyncReadInterval = value; + } + + /// + public TimeSpan? AutoSyncWriteInterval + { + get => _tag.AutoSyncWriteInterval; + set => _tag.AutoSyncWriteInterval = value; + } + + /// + public DebugLevel DebugLevel + { + get => _tag.DebugLevel; + set => _tag.DebugLevel = value; + } + + public event EventHandler ReadCompleted; + public event EventHandler WriteCompleted; + + private void Configure() + { + var tagTypeBytes = _tag.GetByteArrayAttribute("raw_tag_type_bytes"); + var tagTypeCode = BitConverter.ToUInt16(tagTypeBytes, 0); // Endianess? + + switch (tagTypeCode) + { + case 0xC1: // BOOL: Boolean value + decoder = (tag, offset) => tag.GetBit(offset); + encoder = (tag, offset, value) => tag.SetBit(offset, value); + break; + + case 0xC2: // SINT: Signed 8-bit integer value + decoder = (tag, offset) => tag.GetInt8(offset); + encoder = (tag, offset, value) => tag.SetInt8(offset, value); + break; + + case 0xC3: // INT: Signed 16-bit integer value + decoder = (tag, offset) => tag.GetInt16(offset); + encoder = (tag, offset, value) => tag.SetInt16(offset, value); + break; + + case 0xC4: // DINT: Signed 32-bit integer value + decoder = (tag, offset) => tag.GetInt32(offset); + encoder = (tag, offset, value) => tag.SetInt32(offset, value); + break; + + case 0xC5: // LINT: Signed 64-bit integer value + decoder = (tag, offset) => tag.GetInt64(offset); + encoder = (tag, offset, value) => tag.SetInt64(offset, value); + break; + + case 0xC6: // USINT: Unsigned 8-bit integer value + decoder = (tag, offset) => tag.GetUInt8(offset); + encoder = (tag, offset, value) => tag.SetUInt8(offset, value); + break; + + case 0xC7: // UINT: Unsigned 16-bit integer value + decoder = (tag, offset) => tag.GetUInt16(offset); + encoder = (tag, offset, value) => tag.SetUInt16(offset, value); + break; + + case 0xC8: // UDINT: Unsigned 32-bit integer value + decoder = (tag, offset) => tag.GetUInt32(offset); + encoder = (tag, offset, value) => tag.SetUInt32(offset, value); + break; + + case 0xC9: // ULINT: Unsigned 64-bit integer value + decoder = (tag, offset) => tag.GetUInt64(offset); + encoder = (tag, offset, value) => tag.SetUInt64(offset, value); + break; + + case 0xCA: // REAL: 32-bit floating point value, IEEE format + decoder = (tag, offset) => tag.GetFloat32(offset); + encoder = (tag, offset, value) => tag.SetFloat32(offset, value); + break; + + case 0xCB: // LREAL: 64-bit floating point value, IEEE format + decoder = (tag, offset) => tag.GetFloat64(offset); + encoder = (tag, offset, value) => tag.SetFloat64(offset, value); + break; + + case 0xCC: // Synchronous time value + case 0xCD: // Date value + case 0xCE: // Time of day value + case 0xCF: // Date and time of day value + case 0xD0: // Character string, 1 byte per character + case 0xD1: // 8-bit bit string + case 0xD2: // 16-bit bit string + case 0xD3: // 32-bit bit string + case 0xD4: // 64-bit bit string + case 0xD5: // Wide char character string, 2 bytes per character + case 0xD6: // High resolution duration value + case 0xD7: // Medium resolution duration value + case 0xD8: // Low resolution duration value + case 0xD9: // N-byte per char character string + case 0xDA: // Counted character sting with 1 byte per character and 1 byte length indicator + case 0xDB: // Duration in milliseconds + case 0xDC: // CIP path segment(s) + case 0xDD: // Engineering units + case 0xDE: // International character string (encoding?) + throw new NotImplementedException(); + } + } + } + + } +}