TwinCAT3 - ADS - schreiben von Variablen struct mit array

Kurt

Level-2
Beiträge
463
Reaktionspunkte
17
Zuviel Werbung?
-> Hier kostenlos registrieren
TC3 4022.22, ADSdll 4.2.166.0


TC Typen und Variable (vereinfacht)
Code:
TYPE ST_WorkList_1 :
STRUCT
    dnPcsCounter: UDINT;
    lrSheetlength: LREAL;
    arPointData : ARRAY[0..1] OF ST_WorkPoint;
END_STRUCT
END_TYPE
TYPE ST_WorkPoint :
STRUCT
    bActive: BYTE;
    lrLength: LREAL;
    lrBendingPos: LREAL;
END_STRUCT
END_TYPE

stProdList: ST_WorkList_1; // im Namespace HMI also HMI.stProdList

// C# Datendefinition
Code:
    [Serializable]
    [StructLayout(LayoutKind.Sequential, Pack = 0)]
    public class WorkList
    {
        //public string sName;
        public uint nCountPcs;
        public double lrSheetlength;
        public double lrRadius;
        public double lrBendPreposition;
        public double lrProductionSpeed;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] // test mit und ohne Marshal
        public WorkPoint[] arPointData = new WorkPoint[2];

        public WorkList()
        {
            ;
        }
    }

    [Serializable]
    [StructLayout(LayoutKind.Sequential, Pack = 0)]
    public class WorkPoint
    {
        public byte bActive;
        public double lrLength;
        public double lrBendingPos;

        public WorkPoint()
        {
            ;
        }
    }

LESEN funktioniert:
Code:
 string plcVarName = "HMI.stProdList";
data = (WorkList) AdsConnect.Connection.ReadSymbol(plcVarName, typeof (WorkList), true);

SCHREIBEN krieg ich nicht hin
Code:
// WriteAny schreibt die erste struktur correct, das array hat  illegale werte
 var symbolInfo = AdsConnect.Connection.ReadSymbolInfo(plcVarName);
 AdsConnect.Connection.WriteAny((uint)symbolInfo.IndexGroup, (uint)symbolInfo.IndexOffset, data);
Code:
// WriteSymbol bringt Exception: "Memory stream is not expandable."
 AdsConnect.Connection.WriteSymbol(plcVarName, prodData, true); // egal ob true oder false
Code:
// ADSstream schreibt ab der ersten lreal mist in die Spsvariable
AdsStream dataStream = new AdsStream();
BinaryWriter binWrite = new BinaryWriter(dataStream);
dataStream.Position = 0;
              
binWrite.Write(prodData.nCountPcs);
binWrite.Write(prodData.lrSheetlength);
foreach (var sample in prodData.arPointData)
{
     binWrite.Write(sample.bActive);
     binWrite.Write(sample.lrLength);
     binWrite.Write(sample.lrBendingPos);
}

var hVar = AdsConnect.Connection.CreateVariableHandle(plcVarName);
AdsConnect.Connection.Write(hVar, dataStream);

hat jemand einen tipp, wie das Schreiben von zusammegesetzten vars funktioniert.
die infosysbeispiele helfen mir nicht sehr.

kurt
 
Mal so eben aus der Hüfte geschossen (habe mir das Beispiel jetzt nicht im Detail angeschaut).

Wieso Pack-Mode = 0? TC3 nutzt ein 8 Byte Alignment und in deinem Typ ST_WorkPoint ist das relevant. (Alignment in TC3 per Attribute umändern oder eben "hier" per Marshalling)
bild.jpg

Guga
 
Link =Tc2=1 Byte alignement (fuer x86 systeme).
Tc3 ist immer 8 Byte aligned

Guga
 
Zuletzt bearbeitet:
Da ich nicht erfolgreich war, hab ich den Hersteller kontaktiert:
Seine Lösung:

SPS Definition:
Code:
TYPE ST_WorkList_1 :
STRUCT
    dnPcsCounter: UDINT;
    lrSheetlength: LREAL;
    arPointData : ARRAY[0..1] OF ST_WorkPoint;
END_STRUCT
END_TYPE
TYPE ST_WorkPoint :
STRUCT
    bActive: BYTE;
    lrLength: LREAL;
    lrBendingPos: LREAL;
END_STRUCT
END_TYPE
// Variable:
    stProdList: ST_WorkList_1;

Datendefinition im C# prog
Code:
    [StructLayout(LayoutKind.Sequential, Pack = 0)]
    public class WorkList
    {
        public uint nCountPcs;
        public double lrSheetlength;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] 
        public WorkPoint[] arPointData;

        public WorkList()
        {
            arPointData = new WorkPoint[2];
        }
    }

    public struct WorkPoint  // Anmerkung: warum hier struct sein muss und keine class ?
    {
        public byte bActive;
        public double lrLength;
        public double lrBendingPos;

        public WorkPoint(byte bActive, double lrLength, double lrBendingPos)
        {
            this.bActive = bActive;
            this.lrLength = lrLength;
            this.lrBendingPos = lrBendingPos;
        }
    }

Lesen und schreiben mit Any:
Code:
private string plcVarName = "HMI.stProdList";
private WorkList _worklist = new WorkList();

var handle = Connection.CreateVariableHandle(plcVarName);
_worklist = (WorkList)Connection.ReadAny(handle, typeof(WorkList));

var symbolInfo = Connection.ReadSymbolInfo(plcVarName);
Connection.WriteAny((uint)symbolInfo.IndexGroup, (uint)symbolInfo.IndexOffset, _worklist);

ich habs probiert TC3 4022.22 64Bit und es funktioniert.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Structs are value types and classes are reference types.
Du willst keinen Pointer auf irgendwohin im Speicher (class) anbieten sondern tatsächlich die Werte (struct).

Guga
 
Zurück
Oben