senden von klassen an die sps mit c#

spsbeginnerin

Level-1
Beiträge
7
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,
ich muss mit c# komplexe strukturen an die sps senden.
solange das einfache datentypen sind funktioniert das auch alles über WriteAny().
dafür von der beckhoffseite:

Wenn Arrays, Strings oder boolsche Werte in einer Struktur/Klasse definiert sind, muss man festlegen, wie diese gemarshallt werden. Dies geschieht mit Hilfe des MarshalAs Attributs. Da Arrays und Strings unter .Net normalerweise keine feste Länge haben, muss mit dem Property SizeConst die Grösse des Arrays bzw. des Strings festgelegt werden. Das Marshallen von Mehrdimensionale Arrays oder Arrays von Strukturen ist mit dem Marhaler des .NET Frameworks 1.1 nicht möglich. Mehrdimensionale Arrays müssten auf eindimensionale Arrays abgebildet werden. Arrays von Strukturen müssten in der .NET Struktur aufgelöst werden.
In dem Beispiel wird das MarshalAsAttribute in der Klasse ComplexStruct verwendet:
[StructLayout(LayoutKind.Sequential, Pack=1)] // TwinCAT2->Pack=1 TwinCAT3->Pack=0
public class ComplexStruct
{
public short intVal;
//specifies how .NET should marshal the array
//SizeConst specifies the number of elements the array has.
[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
public int[] dintArr = new int[4];
[MarshalAs(UnmanagedType.I1)]
public bool boolVal;
public byte byteVal;
//specifies how .NET should marshal the string
//SizeConst specifies the number of characters the string has.
//'(inclusive the terminating null ).
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=6)]
public string stringVal = "";
public SimpleStruct simpleStruct1 =new SimpleStruct();
}
bei mir konkret:

[StructLayout(LayoutKind.Sequential, Pack = 0)]


public class C1
{
private bool _exist;
private short _numb;



private Pos _pos;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =5)]
private string _liquid;


private float _volume;
private Pos _pos2;
}

[StructLayout(LayoutKind.Sequential, Pack = 0)]//this is necessary in order to use a handler for a struct
public class Pos
{


private short _id;//
[MarshalAs(UnmanagedType.I1)]
private bool _o;
private short _a;
private float _x; //
private float _y; //
private float _z; //
}


in der SPS:

TYPE ST_Class1 :
STRUCT
bExist : BOOL;
nNumb : INT;
sPos : ST_Position;
sLiquid : STRING;
fVolume : REAL;
sPos2 : ST_Position;

END_STRUCT
END_TYPE



Das funktioniert leider nicht ein class1-objekt zu senden. Also an die sps nur ein Pos senden geht und auch ein Array von Pos.
Der Anfang stimmt überein, aber hinter dem String also die Werte des floats volume und des 2. pos werden nicht mit übertragen.
Wenn ich den String liquid aber rausnehme, dann klappt das.
liegt das an dem string? wie kann ich strings darin mitversenden, damit es funktioniert? welche größe (Marshall As) muss ich dem string geben?
 
Zuletzt bearbeitet:
Hallo,

in CODESYS haben Strings eine feste Länge und sind 0-terminiert. Die Länge eines Strings kann in IEC61131 angegeben werden oder hat eine Default-Länge (bitte in Hilfe nachlesen oder mal mit SIZEOF nachprüfen). In .Net werden die Strings anders gehandhabt: Sie fangen mit einer 1-4 bytes Längenangabe an und dann folgt der String ohne Terminierung. Mit einem MarshallAs-Attribut unter Angabe einer SizeConst könnte es funktionieren. Aber Achtung: Ein IEC-String(80) hat eine Länge von 81 byte, da die 0-Terminierung noch dahinter kommt.

Gruß

Thomas
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Danke, mit feste größe = 81 hat es funktioniert.

Jetzt geth es darum, dass ich diese Klasse: C1 in einem Array als Teil einer anderen Klasse senden möchte:

[StructLayout(LayoutKind.Sequential, Pack = 0)]



public class C1
{
private bool _exist;
private short _numb;

private Pos _pos;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =5)]
private string _liquid;
private float _volume;

private Pos _pos2;
}

public abstract class W
{
#region Members
protected short _iD;
[MarshalAs(UnmanagedType.I1)]
protected bool _exist;
[MarshalAs(UnmanagedType.I1)]
protected bool _open;
protected short _type;


// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 96)]
protected C1[] _c1;
}

mit dem Konstruktor:
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public class W2 : W
{
public W2()
{
_iD = 0;
_exist = false;
_open = true;
_type=0;

_c1 = new C1[96];
for (int i = 0; i < 96; i++)
{
_c1 = new C1();
}
}

TYPE ST_W:
STRUCT
nID : INT;
bExist : BOOL:=0;
bOpen : BOOL;
eType : E_Type;

arC1 : ARRAY[1..96] OF ST_C1;
END_STRUCT
END_TYPE




Wenn ich dann in der Main ein W2 erstelle, und das an die SPS sende, dann funktioniert das nicht....da sind dann in dem Array irgendwelche absurden werte teilweise.

Wenn ich zb zunächst manuell werte eintrage für das erste C1-Element aus dem C1-Array in W2 und danach in c# ein w2 instanz ( alle werte auf 0 oder false gesetzt) erstelle, wird das nicht über
in C1(in 1.Element des arC1) steht in einem bool exist, <Der Wert des Ausdrucks kann nicht gelesen werden.>, bei dem int numb eine absurd große zahl und das Element Pos (was ja auch ein struct ist, wird nicht überschrieben, auch wenn in C# ja ein leeres mit instanziert worden ist.
woran könnte das liegen?
irgendwie passt dasnicht mit der speicherumwandlung.... zb ist es ja auch, dass in C1 beschreibe ich für die Klasse Pos ja nicht extra das MashallAs Attribut, weil ich in der Klassendefinition von Pos ja das structlayout defniiert habe. muss ich das doch machen? und wenn ja, woher weiß ich dann welche größe es haben soll?

falls das zu kompliziert alles ist, kann mir jemand nochmal genau erklären, wann man marshallas (und wiegenau) benutzen muss?

bisher benutze ich nur die WrityAny-Methode, die ja beliebige structs senden kann (eigentlicih). Gibt es sonst eine andere Möglichkeit, wenn ich das Problem nicht lösen kann?

Vielen Dank
 
Zuletzt bearbeitet:
Konkret geht es um dieses:
public abstract class W
{
#region Members
protected short _iD;
[MarshalAs(UnmanagedType.I1)]
protected bool _exist;
[MarshalAs(UnmanagedType.I1)]
protected bool _open;
protected short _type;


// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 96)]
protected C1[] _c1;
}

was muss da stehen? oder muss da überhaupt was stehen? ich habe da 96 hingeschrieben, weil das Array was dann von C1 kreiert wird, 96 einträge hat, allerdings ja von C1 welches nicht nur 1 byte groß ist. müsste es dann 96*sizeof(C1)?


wenn der Text oben zu kompliziert war, könnte man es auch vereinfacht hierdran sehen:

es gibt die Klasse

//complex
C1{
bool b1;
short s1;
C2 c2;
}

//simple
C2{
short s1;
short s2;
}

//more complex
W1{
short s1;
C2 c2;
C1 [] c1;
}


Kann ich W1 jetzt mit der WriteAny-Methode senden?
Muss ich dann vorher mit MarshallAs über dem C1-Array sagen wie groß es ist? (Woher weiß ich, wie groß es ist?)
 
Zurück
Oben