using Iec61131.Engineering.Prototypes.Common; using Iec61131.Engineering.Prototypes.Methods; using Iec61131.Engineering.Prototypes.Pragmas; using Iec61131.Engineering.Prototypes.Types; using Iec61131.Engineering.Prototypes.Variables; using System; using System.Iec61131Lib; using System.Runtime.InteropServices; namespace T256720 { // Here is the array type that will be used as Struct fields // The IecArray must be defined as a struct with a fixed size. // The array definition MUST have following Attributes: // 1. Array (Actually only one-dimensional arrays are supported by the PCWorx Engineer) // 2. ArrayDimension // 3. DataType to define the data type of the array elements [Array(1), ArrayDimension(0, ArrayProperties.LowerBound, ArrayProperties.UpperBound), DataType("DINT")] [StructLayout(LayoutKind.Explicit, Size = ArrayProperties.ByteSize)] public struct ArrayType1 { // Helper containing constants to have a // clear and maintainable definition for boundaries and size private struct ArrayProperties { public const int LowerBound = -10; // must not necessarily being zero, it also can be negative public const int UpperBound = 9; // IEC61131 representation is : userArray : ARRAY[-10..9] OF DINT (* size == 20 *) // the size must be changed to the correct size of your elements times the amount of elements public const int ByteSize = (UpperBound - LowerBound + 1) * sizeof(int); } public const int ByteSize = ArrayProperties.ByteSize; // Fields // The field "Anchor" defines the beginning of the array. [FieldOffset(0)] // The Anchor's data type is the child data type of the array public int Anchor; // The constants LB and UB define the upper and lower bound. Boundaries will be checked by using them. public const int LB = ArrayProperties.LowerBound; public const int UB = ArrayProperties.UpperBound; public int this[int index] { get { if (index >= (LB - ArrayProperties.LowerBound) && index <= (UB - ArrayProperties.LowerBound)) { unsafe { fixed (int* pValue = &Anchor) { int result = *(pValue + index); return result; } } } else { throw new IndexOutOfRangeException(); } } set { if (index >= (LB - ArrayProperties.LowerBound) && index <= (UB - ArrayProperties.LowerBound)) { unsafe { fixed (int* pValue = &Anchor) { *(pValue + index) = value; } } } else { throw new IndexOutOfRangeException(); } } } } //// Define a string data type with a maximum string length of 200 characters //// Size is string length + 4 byte header + 1 byte terminating zero + padding for two byte alignment //// Mark the declaration with a String attribute and define the length //[String(200)] //[StructLayout(LayoutKind.Explicit, Size = 206)] //public struct TString200 //{ // // Fields // [FieldOffset(0)] // public IecStringEx s; // This member must have the name 's' because the name is evaluated by PLCnext Engineer! // // Methods // // Init is needed to set the maximum size and called in the initialization // public void Init() // { // s.maximumLength = 200; // s.Empty(); // } //} // Here is the structure type [Structure] public struct StructType { public ArrayType1 Array_A; public ArrayType1 Array_B; public IecString80 String_A; // The string variable must be explicitly initialised public void Init() { String_A.ctor(); } } // Here is the array type // The IecArray must be defined as a struct with a fixed size. // The array definition MUST have following Attributes: // 1. Array (Actually only one-dimensional arrays are supported by the PCWorx Engineer) // 2. ArrayDimension // 3. DataType to define the data type of the array elements [Array(1), ArrayDimension(0, ArrayProperties.LowerBound, ArrayProperties.UpperBound), DataType("StructType")] [StructLayout(LayoutKind.Explicit, Size = ArrayProperties.ByteSize)] public struct ArrayType2 { // Helper containing constants to have a // clear and maintainable definition for boundaries and size private struct ArrayProperties { public const int LowerBound = 1; // must not necessarily being zero, it also can be negative public const int UpperBound = 8; // IEC61131 representation is : userArray : ARRAY[1..8] OF StructType (* size == 8 *) public const int ElementSize = (40 * sizeof(int)) + 86; // bytes. THIS IS HARD-CODED AND MUST BE CHANGED IF THE STRUCT CHANGES. // the size must be changed to the correct size of your elements times the amount of elements // For hints on how to calculate the size of a structure, see: // https://github.com/PLCnext/CSharpExamples/blob/master/PLCnext_CSharpExamples/04_UserArray/UserArray.md public const int ByteSize = (UpperBound - LowerBound + 1) * ElementSize; } public const int ByteSize = ArrayProperties.ByteSize; // Fields // The field "Anchor" defines the beginning of the array. [FieldOffset(0)] // The Anchor's data type is the child data type of the array public StructType Anchor; // The constants LB and UB define the upper and lower bound. Boundaries will be checked by using them. public const int LB = ArrayProperties.LowerBound; public const int UB = ArrayProperties.UpperBound; public StructType this[int index] { get { if (index >= (LB - ArrayProperties.LowerBound) && index <= (UB - ArrayProperties.LowerBound)) { unsafe { fixed (StructType* pValue = &Anchor) { StructType result = *(pValue + index); return result; } } } else { throw new IndexOutOfRangeException(); } } set { if (index >= (LB - ArrayProperties.LowerBound) && index <= (UB - ArrayProperties.LowerBound)) { unsafe { fixed (StructType* pValue = &Anchor) { *(pValue + index) = value; } } } else { throw new IndexOutOfRangeException(); } } } public void Init() { unsafe { fixed (StructType* ptr = &this.Anchor) { for (int i = 0; i < UB - LB + 1; i++) { ptr[i].Init(); } } } } } [FunctionBlock] public class FunctionBlock1 { [Input] public ArrayType2 arrPara; [Output, DataType("DINT")] public int iFilter_1; [Output, DataType("DINT")] public int iSensortype_8; int ideVal; [Initialization] public void __Init() { // Since the custom array contains String variables, // the array (and therefore the String variables) // must be explicitly initialised. arrPara.Init(); } [Execution] public void __Process() { // Loop over the array element. // NOTE: C# ARRAYS ALWAYS START AT INDEX 0 for (ideVal = 0; ideVal <= 7; ideVal++) { if (ideVal == 0) iFilter_1 = arrPara[ideVal].Array_A[0]; if (ideVal == 7) iSensortype_8 = arrPara[ideVal].Array_B[20]; } } } }