6

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 });
Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
V P
  • 91
  • 3
  • 10

1 Answers1

7

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

Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
  • Thanks Mong Zhu for your response. I have that array variable defined in PLC and Forget to mentioned in post. Also `handles[0]` is pointing to correct array variable. As I mentioned in post, code is reading the values correctly but throwing error in writing. I thing I'm missing or doing something wrong in marshaling the struct properties. Would you please try with same struct definition that I have. – V P Aug 23 '16 at 08:30
  • I actually tried exactly the struct definition that you have, see my edit. – Mong Zhu Aug 23 '16 at 08:32
  • I'm not seeing any updates in you post. would you please help me to identify it? – V P Aug 23 '16 at 08:37
  • @VP sorry, was a little slow – Mong Zhu Aug 23 '16 at 08:38
  • @VP are you still using `adsClient.WriteAny(handles[0], stations, new int[] { 5 });` to write the structure to the PLC ? – Mong Zhu Aug 23 '16 at 08:39
  • Thanks Mong Zhu. Only difference in your code is, you are not passing int[]args parameter (third parameter) in WriteAny method. Is it causing the error? – V P Aug 23 '16 at 08:46
  • that actually might be, I wondered why you do this. Where did you find this example? I never used the params array before and everything worked fine :) – Mong Zhu Aug 23 '16 at 08:54
  • I dont have access to this application at this time so i will try after removing that parameter later sometime. Will surely let you know it worked out for me or not. Hopefully it will :) – V P Aug 23 '16 at 08:58
  • 1
    I kept everything as it is as I have in actual code and just removed last parameter `new int[] { 5 }` and it is working. I mistaken the last parameter as length of array. That parameter is useful when writing fixed character string value and have to provide it during write operation. Thanking you Mong Zhu for your help. – V P Aug 24 '16 at 13:23