Hello, can you explain me how to use arrays as output in C#? I have defined a struct with array attributes to create and use the same type in pc worx engineer. Here is my defined struct: [Array(1), ArrayDimension(0, 1, 4096), DataType(“BYTE”)]
public struct Array_4096
{
public byte Array;
} I am using this array in a function block like this: [FunctionBlock]
public class FunctionBlock2
{
[Input, DataType(nameof(Array_4096))]
public Array_4096 NewArray;
[Initialization]
public void __Init()
{
// TODO: Initialize the variables of the function block here
NewArray.Array = new byte[4096];
for(int i = 0; i < 50; i++)
{
NewArray.Array[i] = (byte) i;
}
}
[Execution]
public void __Process()
{
}
} When i use this function block in a pc worx engineer program, i cant access or see the array values (see attached picture) . I would expect to see the 50 values set in init method. Best regards Stefan
Hi Stefan, as far as I can see, Arrays in C# are differentlly handled then in PCWorx Engineer. There has been a post about this before but I can’t find it for the moment. Oliver from Phoenix will come with some more informations when he is back from the vacation. I have seen so far, that we have a few limitations to the “standard” C# functions we may know from Visual Studio compared with the one we can use in PLC Next. Make notes of what you find and post it on the forum so that we all see where some work has to be done. I have seen, that the “stream” function from C# doesn’t work in PLC Next. Wanted to read single bits of a short INT. We have to see about those limits. I would guess that Phoenix will come with a list with functions that are supported and some work-arounds in the near future. Peter
@Emilg yep, I have noticed that. Good to have someone that keeps track on things here. can see you have started to play with C#. Dan has started too. I hope that we can fix a workshop after SPS and drives with Dan. So we can pull recurces to find some solutions and to get things rolling. Peter
Hi Stefan, The implementation of an IEC Array needs the PLCnext specific attributes, Array(), ArrayDimension() and DataType().
Furthermore the StructLayout() with the “Anchor” field as FieldOffset() and the full implementation with the possiblity to use the index operator. See the attached example:
using System;
using System.Iec61131Lib;
using Eclr;
using Eclr.Pcos;
using System.Runtime.InteropServices;
using Iec61131.Engineering.Prototypes.Types;
using Iec61131.Engineering.Prototypes.Variables;
using Iec61131.Engineering.Prototypes.Methods;
using Iec61131.Engineering.Prototypes.Common;
namespace EclrFirmwareLibrary2
{
[Array(1), ArrayDimension(0, 0, 511), DataType("BYTE")]
[StructLayout(LayoutKind.Explicit, Size = 512)]
public struct SE_CS_arrByte_0_511
{
// 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 byte Anchor;
// The constants LB and UB define the upper and lower bound. Boundaries will be checked by using them.
public const int LB = 0;
public const int UB = 511;
public byte this[int index]
{
get
{
if (index >= LB && index <= UB)
{
unsafe
{
fixed (byte* pValue = &Anchor;)
{
return *(pValue + index);
}
}
}
else
{
throw new IndexOutOfRangeException();
}
}
set
{
if (index >= LB && index <= UB)
{
unsafe
{
fixed (byte* pValue = &Anchor;)
{
*(pValue + index) = value;
}
}
}
else
{
throw new IndexOutOfRangeException();
}
}
}
public void Fill(byte value = 0x00)
{
unsafe
{
fixed (byte* pValue = &Anchor;)
{
for (int index = LB; index <= UB; index++)
{
*(pValue + index) = value;
}
}
}
}
}
[FunctionBlock]
public class FunctionBlock1
{
[Input]
public short Index;
[Input]
public byte Value;
[Output, DataType(nameof(SE_CS_arrByte_0_511))]
public SE_CS_arrByte_0_511 OUT;
[Initialization]
public void __Init()
{
OUT.Fill(0x00);
}
[Execution]
public void __Process()
{
OUT[Index] = Value;
}
}
}
Hi Björn, thanx for the example. How about the handling of WORD variables in C#? The type WORD does not exist in C# but is used in the standard PLC programming. I have tried to go via short int and the STREAM function in C# to read the single bits of the WORD (short Int) but it looks we have some restrictions. When I run my program as a consol application it did work, but when running it on the AXC F 2152 it did not. Any suggestions on how to handle it? Peter
[FunctionBlock]
public class FunctionBlock2
{
[Input]
public short IN1;
[Input]
public short IN2;
[Output, DataType("WORD")]
public ushort OUT;
[Initialization]
public void __Init()
{
}
[Execution]
public void __Process()
{
OUT = (ushort)(IN1 + IN2);
}
}
See the attached table for the type mapping. (Copied from the C# project template readme.txt)
Hello together, I already answered the initial question via mail and forgot to write it here. I have a bunch of C# samples available, like best practice for C# in PLCnext. At the moment I am not allowed to publish it because of liability reasons and it has no claim to correctness and completeness. But I am allowed to send it via email if you contact me mluhmann (at) phoenixcontact.com. As Björn already said, the Readme.txt in each new firmware library project contains the data type mapping table and in the Documentation folder is an online documentation (eCLR-Programming-Reference.chm). This contains a library reference and the information about limitations (known issues and constraints) of C# in PLCnext. Marcel
This exception means that you’re trying to access a collection item by index, using an invalid index. An index is invalid when it’s lower than the collection’s lower bound or greater than or equal to the number of elements it contains. whenever we try to access a C# array or collection, etc. we can only access the existing indexes in the array. array[0] and array[1] are existing. If we try to access array[3], it’s not there actually, so an index out of bound exception will arise. Typically, an IndexOutOfRangeException exception is thrown as a result of developer error. Instead of handling the exception, you should diagnose the cause of the error and correct your code.