Write array of struct using TwinCAT.Ads through C# application

5.9k Views Asked by At

I’m using TwinCAT.Ads (TwinCAT 3) for Beckhoff plc communication through c# application. Application is reading and writing few plc variables. I’m getting an error:

“Unable to marshal object. Parameter name: value”

while writing an array of struct variable. However application is reading it without any error. Any help will be appreciated. Below is my code sample.

Struct in Plc

TYPE Station :
    STRUCT
        ClusterID   : STRING[10];
        Tech_Type   : USINT;
        Status      : BOOL;
        Reject      : BOOL;
        Rej_Detail  : STRING[50];
        Rej_Catagory : USINT; 
    END_STRUCT
END_TYPE

Class in c#

[StructLayout(LayoutKind.Sequential, Pack = 0)]
public class Station
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
    public string ClusterID;
    public byte Tech_Type;
    [MarshalAs(UnmanagedType.I1)]
    public bool Status;
    [MarshalAs(UnmanagedType.I1)]
    public bool Reject;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 51)]
    public string Rej_Detail;
    public byte Rej_Catagory;
}

I’m writing with below code where handles[0] is variable handle and stations is array of class with length of 5.

adsClient.WriteAny(handles[0], stations, new int[] { 5 });
1

There are 1 best solutions below

9
On BEST ANSWER

I guess you are missing the counterpart in the PLC. Please make sure that in your PLC you have declared an array of stations something like:

// I have it in a global variable list named: STG_Variables
stat_array_Var : array [0..5] of Station;

This C# code works for me:

TcAdsClient AdsComClient = new TcAdsClient();
AdsComClient.Connect(NetID_TwinCat, 851);

int handle_array = AdsComClient.CreateVariableHandle("STG_Variables.stat_array_Var");

// get some test stations:
Station station = new Station();
Station station2 = new Station();
Station station3 = new Station();
Station station4 = new Station();
Station station5 = new Station();

Station[] station_plural = new Station[] { station, station2, station3, station4, station5 };

// write some stuff to recognize that write test worked
for (int i = 0; i < station_plural.Length; i++)
{
    station_plural[i].ClusterID = "ID: " + i.ToString();
}

// just use the normal WriteAny method without the new int[] { 5 } parameter!
// send it down to the plc
AdsComClient.WriteAny(handle_array, plural);

I don't know where your handle handles[0] points at. writing an array of Station should not end up in one single struct in the plc. Try my version and please comment on whether it worked out for you.

EDIT: I used this class definition in C#:

[StructLayout(LayoutKind.Sequential, Pack = 0)]
public class Station
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
    public string ClusterID;
    public byte Tech_Type;
    [MarshalAs(UnmanagedType.I1)]
    public bool Status;
    [MarshalAs(UnmanagedType.I1)]
    public bool Reject;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 51)]
    public string Rej_Detail;
    public byte Rej_Catagory;
}

and created a DUT and used this struct definition in the PLC:

TYPE Station :
STRUCT
    ClusterID   : STRING[10];
    Tech_Type   : USINT;
    Status      : BOOL;
    Reject      : BOOL;
    Rej_Detail  : STRING[50];
    Rej_Catagory : USINT; 
END_STRUCT
END_TYPE

and declared the array variable of Stations as described above.

And it works. I am able to write the structure down to the PLC and see the "ID: 0" , "ID: 1" , "ID: 2" and so on strings in the array