Skip to content

Return Array From C# FB

I would like to return a ushort[] from a C# FB. My thought was I could do this using a DataType of "ANY" in the FB: 

   [Output, DataType("ANY")]

   public ushort[] Result;

 

Then in PCWE I created the following data type:

    RegisterArray : ARRAY[0..100] of UINT;

 

That resulted in an error, "operation not legal in this context". Is it possible to return an array from a C# FB?

Comments

  • Hi Rob, sorry for the delay.

    It is possible to pass both arrays and structures as parameters on a C# FB.

    This is not documented in the Help files yet, but I have some sample code that I will post here tomorrow (Thursday) when I'm back in the office. It's not trivial but basically you will define the structure (or array) in your C# code as a user-defined type, using an Unsafe block of code to access memory using pointers. This custom type will be exported with your FB and you can then use this type to declare variables in PC Worx Engineer.

    You could also use the general ANY data type to pass an array - in this case the variable in the C# code must also be declared as type Any (not ushort[]) and you must then use unsafe code to access data in the ANY variable using pointers ... and just trust that the caller is using the expected data type on their side. This is not as neat as defining your own array type and forcing the caller to use that type when calling your FB.

    - Martin.

     

  • Hi Rob,

    I've just realised that community member Björn posted a good answer to a similar question a few months ago:

    https://plcnext-community.net/index.php?option=com_easydiscuss&view=post&id=903&Itemid=224&lang=en

    Here's how you might declare the array in your specific case (put this in your source file before the class definition) - including comments that I hope are useful.

        // Declare User-Defined types that can be used in IEC 61131 programs.
        //
        // Notes:
        //  - The definition of these types is not visible in PLCnext Engineer,
        //    so separate user documentation is important.
        //  - If a PLCnext Engineer project uses two libraries that define data types with the same name,
        //    then that PLCNE project will not compile. Define data types with names that are likely to be unique.
        //  - This uses unsafe code, so the "Allow unsafe code" option must be checked in
        //    the Project Properties window (Project -> Properties -> Build).
        //
        // IecArrays must be defined as a struct with a fixed size.
        // The array definition MUST have following Attributes:
        // 1. Array (Currently only one-dimensional arrays are supported by PLCnext Engineer)
        // 2. DataType of the array elements
        // 3. ArrayDimension, specifying the upper and lower bounds of each dimension
        // The size of the struct is calculated by: (size of single element) x (total number of elements)
    
        [Array(1), DataType("UINT"), ArrayDimension(0, 0, 100)]
        [StructLayout(LayoutKind.Explicit, Size = 202)]
        public struct MY_ARRAY
        {
            // Fields
            // The field "Anchor" defines the beginning of the array.
            // The value of the FieldOffset attribute must always be zero.
            [FieldOffset(0)]
            // The Anchor's data type is the child data type of the array.
            public ushort Anchor;
            // The constants LB and UB define the upper and lower bound.
            public const int LB = 0;
            public const int UB = 100;
            // 'this' function must return the data type of the array.
            public ushort this[int index]
            {
                get
                {
                    if ((index >= LB) && (index <= UB))
                    {
                        unsafe
                        {
                            fixed (ushort* pValue = &Anchor)
                            {
                                byte ushort = *(pValue + index - LB);
                                return result;
                            }
                        }
                    }
                    else
                    {
                        throw new IndexOutOfRangeException();
                    }
                }
                set
                {
                    if ((index >= LB) && (index <= UB))
                    {
                        unsafe
                        {
                            fixed (ushort* pValue = &Anchor)
                            {
                                *(pValue + index - LB) = value;
                            }
                        }
                    }
                    else
                    {
                        throw new IndexOutOfRangeException();
                    }
                }
            }
        }
    

     

    You would then declare your output variable as:

    [Output, DataType("MY_ARRAY")]
    public MY_ARRAY Result;
    

     

    In PC Worx Engineer, you must then declare a variable of type MY_ARRAY to connect to this FB parameter. This data type is imported with your library, so there's no need to create a new Data Type for this in PCWE.

    - Martin.

  • edited April 2023

    Hi Martin

    I have problems with these two lines. What is wrong?

          byte ushort = *(pValue + index - LB);

          return Result;

    What would it look like for an Input Array?

    Can have both Input Array and Output Array in same FB?

    What should I modify in order to hold "DOUBLE" in the arrays?

  • Please try the User Array example in Github, in the C# Examples repository :

    That should compile OK.

    What would it look like for an Input Array?

    The example in Github shows how to use an array as an input to a function block.

    Can have both Input Array and Output Array in same FB?

    Yes.

    What should I modify in order to hold "DOUBLE" in the arrays?

    The example in Github uses an array of DINT's.

    A table showing the relationship between data types in IEC-61131, .NET, and C#, is given in the Info Center:

    If you want to modify the example to use an array of something other than DINTs, then you would need to change all the instances of int in the array definition in the C# code, to another data type in the third column of the table, e.g. short for an array of INTs, or float for an array of REALs.

    I hope this helps.

Sign In or Register to comment.