Kommunikation VB.NET <--> SPS via ADS.NET

twincatter

Level-1
Beiträge
137
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Programmierer,

Ich habe eine Strukturvariable, z.B.

TYPE MeinStruct :
STRUCT
intVal : INT;
boolVal: BOOL;
END_STRUCT

Mit diesem Datentyp erzeuge ich die Feldvariable, z.B.
MeinArray : ARRAY[0..1] OF MeinStruct;

Die Variablenwerte können problemlos aus dem VB.NET-Programm beschrieben gelesen werden. Es gibt ja einige Möglichkeiten dies zu tun.

Ich möchte aber das komplette Array mit einem einzigen WriteAny bzw. ReadAny schreiben/auslesen. Bei einem einfachen Strukt ist das auch kein Problem. Wenn es sich jedoch um ein Struktarray handelt bringe ich es einfach nicht hin.

Bin für Ideen dankbar, Michael
 
Hallo Michael,

meine deutsch ist nich zo güt also mache ich es in english, wenn sie noch frage hatt könne sie dass in deutsch schicken. :)

Code:
using TwinCAT.Ads;
using System.Runtime.InteropServices;
 
namespace ReadAny
{
 
    public struct strIn
    {
        [MarshalAs(UnmanagedType.I1)]
        bool DigIn1;
        [MarshalAs(UnmanagedType.I1)]
           bool DigIn2;
        [MarshalAs(UnmanagedType.I1)]
        bool DigIn3;
        [MarshalAs(UnmanagedType.I1)]
           bool DigIn4;
 
        short AnaIn1;
           short AnaI2;
           short AnaIn3;
           short AnaIn4;
    }
 
    public struct strOut
    {
        [MarshalAs(UnmanagedType.I1)]
        public bool DigOut1;
        [MarshalAs(UnmanagedType.I1)]
        public bool DigOut2;
        [MarshalAs(UnmanagedType.I1)]
        public bool DigOut3;
        [MarshalAs(UnmanagedType.I1)]
        public bool DigOut4;
 
        short AnaOut1;
        short AnaOut2;
        short AnaOut3;
        short AnaOut4;
    }
    public partial class Form1 : Form
    {
        TcAdsClient tcclient;
        int hVar, hvarOut;
        strIn dataIn;
        strOut dataOut;
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            tcclient = new TcAdsClient();
            tcclient.Connect(801);
 
 
 
            hVar = tcclient.CreateVariableHandle(".GlobalIn");
            dataIn = (strIn)tcclient.ReadAny(hVar, typeof(strIn));
 
            dataOut.DigOut1 = true;
            dataOut.DigOut3 = true;
           
            hvarOut = tcclient.CreateVariableHandle(".GlobalOut");
            tcclient.WriteAny(hvarOut, dataOut);
        }
    }
}

The Datain-readany is also useable to read in arrays :
ftp://ftp.beckhoff.com/belgium/TwinCAT Cursus/Module 4 - Introduction to ADS-Programming.pdf
page 23 more info about it.

the one thing that doesn't work is an array of struct in a struct... :-x
25/04/2012 -> I even got that working now, it's easy once you know how, pm me if you need any more coding to explain it also

best regards,
Peter
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
I have same problem
I want to read and write in VB.net variables of an array structure in textbox for example


TYPE ST_CodeFonction :
STRUCT
Fonction : INT:=1;
Code : WORD:=0;
Attente:TIME:=t#1ms;
Position_Z : REAL:=0;
Position_X : REAL:=0;
Position_R : REAL:=0;
Vitesse_ZXR : REAL:=100;
Position_T : REAL:=0;
Vitesse_T : REAL:=26;
Debit : DWORD:=0;
END_STRUCT
END_TYPE

Mit diesem Datentyp erzeuge ich die Feldvariable, z.B.
MeinArray : ARRAY[0..20] OF ST_CodeFonction;
Zb
TYPE ST_Recette :
STRUCT

Nom : STRING:)cool:;
Recette : ARRAY[1..20] OF ST_CodeFonction;


END_STRUCT
END_TYPE

how kann i do it please I'm looking for 3 semaines.but i not find a solution
 
hi peter
I have a problem
I want to read and write in VB.net variables of an array structure in textbox for example


TYPE ST_CodeFonction :
STRUCT
Fonction : INT:=1;
Code : WORD:=0;
Attente:TIME:=t#1ms;
Position_Z : REAL:=0;
Position_X : REAL:=0;
Position_R : REAL:=0;
Vitesse_ZXR : REAL:=100;
Position_T : REAL:=0;
Vitesse_T : REAL:=26;
Debit : DWORD:=0;
END_STRUCT
END_TYPE

Mit diesem Datentyp erzeuge ich die Feldvariable, z.B.
MeinArray : ARRAY[0..20] OF ST_CodeFonction;
Zb
TYPE ST_Recette :
STRUCT

Nom : STRING:)cool:;
Recette : ARRAY[1..20] OF ST_CodeFonction;


END_STRUCT
END_TYPE

how kann i do it please I'm looking for 3 week.but i not find a solution
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Quick learn..

HI Axeltsob,

I'm not going to explain Marshaling as I'm no .NET expert, but I'll give you a quick run-through :cool:

1st Start with what you already (hopefully) know:
Code:
TYPE ST_CodeFonction :
STRUCT                        (*Handled in .NET as...*)
    bEnable        :    BOOL;        (*Byte sized boolean added this variable for completeness of explanation :ROFLMAO:*)
    Fonction         :     INT:=1;        (*INT16*)
    Code         :     WORD:=0;    (*UINT16*)
    Attente        :    TIME:=t#1ms;    (*UINT32 as in IEC61131 TIME takes Dword size*)
    Position_Z     :     REAL:=0;        (*Single*)
    Position_X     :     REAL:=0;        (*Single*)
    Position_R     :     REAL:=0;        (*Single*)
    Vitesse_ZXR     :     REAL:=100;    (*Single*)
    Position_T     :     REAL:=0;        (*Single*)
    Vitesse_T     :     REAL:=26;    (*Single*)
    Debit         :     DWORD:=0;    (*UINT32*)
END_STRUCT
END_TYPE

would give us in .NET (using c# as I'm not very known in VB.NET):

Code:
    [StructLayout(LayoutKind.Sequential, Pack=1)]
    public class St_CodeFonction
    {
        [MarshalAs(UnmanagedType.I1)]
        public Boolean bEnable;
        public Int16 Fonction;
        public UInt16 Code;
        public UInt32 Attente;
        public Single Position_Z;
        public Single Position_X;
        public Single Position_R;
        public Single Vitesse_ZXR;
        public Single Position_T;
        public Single Vitesse_T;
        public UInt32 Debit;
    }

As the Boolean in the PLC is actual a byte size variable, you have to "explain" it also...

So the code thus far... don't look at the HOW it is shown, rather the WHAT is explained (remember I'm no .Net programmer)...
Code:
using TwinCAT.Ads;
using System.Runtime.InteropServices; //For the marshaling stuff :)

namespace WindowsFormsApplication1
{
    [StructLayout(LayoutKind.Sequential, Pack=1)]
    public class St_CodeFonction
    {
        [MarshalAs(UnmanagedType.I1)]
        public Boolean bEnable;
        public Int16 Fonction;
        public UInt16 Code;
        public UInt32 Attente;
        public Single Position_Z;
        public Single Position_X;
        public Single Position_R;
        public Single Vitesse_ZXR;
        public Single Position_T;
        public Single Vitesse_T;
        public UInt32 Debit;
    }

    public partial class Form1 : Form
    {
        TcAdsClient tcClient = new TcAdsClient();
        St_CodeFonction dataToRead;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            tcClient.Connect(801);

            try
            {
                 dataToRead =  (St_CodeFonction)tcClient.ReadAny(tcClient.CreateVariableHandle(".varTest"),  typeof(St_CodeFonction));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }
    }
}

Now we will step up one further, making it an array of code function without the string... I'll come back to it later in this explanation :wink:

so now for the VarTest as a variable of type
Code:
varTest    :    ST_Recette;
and recette being
Code:
TYPE ST_Recette :
STRUCT
    Recette     :     ARRAY[1..20] OF ST_CodeFonction;
END_STRUCT
END_TYPE

This will give us in .NET:
Code:
using TwinCAT.Ads;
using System.Runtime.InteropServices; //For the marshaling stuff :)

namespace WindowsFormsApplication1
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct St_recette
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        St_CodeFonction[] Recette;
    }

    [StructLayout(LayoutKind.Sequential, Pack=1)]
    public struct St_CodeFonction
    {
        [MarshalAs(UnmanagedType.I1)]
        public Boolean bEnable;
        public Int16 Fonction;
        public UInt16 Code;
        public UInt32 Attente;
        public Single Position_Z;
        public Single Position_X;
        public Single Position_R;
        public Single Vitesse_ZXR;
        public Single Position_T;
        public Single Vitesse_T;
        public UInt32 Debit;
    }

    public partial class Form1 : Form
    {
        TcAdsClient tcClient = new TcAdsClient();
        St_recette dataToRead;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            tcClient.Connect(801);

            try
            {
                dataToRead = (St_recette)tcClient.ReadAny(tcClient.CreateVariableHandle(".varTest"), typeof(St_recette));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }
    }
}

and now for the additional string variable:
This is actually a special case, as it can be any size you want actually... so here we go :ROFLMAO:

if you pnly want to read one string you could get away with
Code:
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 81)]
        public string Nom;

In SPS -> I just made it more interesting and made the string variable also array type, just to show you how powerfull it could become...
Code:
TYPE ST_Recette :
STRUCT
    Nom     :     ARRAY [1..20] OF STRING; (*If no size is given it 80 char +1 for the NULL character so 81 bytes*)
    Recette     :     ARRAY[1..20] OF ST_CodeFonction;
END_STRUCT
END_TYPE

will give us in .NET:
Code:
using TwinCAT.Ads;
using System.Runtime.InteropServices; //For the marshaling stuff :)

namespace WindowsFormsApplication1
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct St_recette
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        public String80[] Nom;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        St_CodeFonction[] Recette;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct String80
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 81)]
        public string String81;

    }    


    [StructLayout(LayoutKind.Sequential, Pack=1)]
    public struct St_CodeFonction
    {
        [MarshalAs(UnmanagedType.I1)]
        public Boolean bEnable;
        public Int16 Fonction;
        public UInt16 Code;
        public UInt32 Attente;
        public Single Position_Z;
        public Single Position_X;
        public Single Position_R;
        public Single Vitesse_ZXR;
        public Single Position_T;
        public Single Vitesse_T;
        public UInt32 Debit;
    }

    public partial class Form1 : Form
    {
        TcAdsClient tcClient = new TcAdsClient();
        St_recette dataToRead;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            tcClient.Connect(801);

            try
            {
                dataToRead = (St_recette)tcClient.ReadAny(tcClient.CreateVariableHandle(".varTest"), typeof(St_recette));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }
    }
}

you could rewrite the .net variable Nom with you're own marshaler, but I didn't investigate that path yet... maybe futher steps, or perhaps if someone else could explain this, would be great! :cool:
It's a lot to go through, but if you have any further questions, just let me know...PM me!

Best regards,
Peter
 
Zuletzt bearbeitet:
Just for completeness:
info on the any type reading Writing in the information system: http://infosys.beckhoff.com/content/1033/tcsample_net/html/twincat.ads.sample07.htm?id=11758

Packsize for x86 (PC's and CX10xx's) = 1;
Packsize for ARM (CX9000's) = 4;
and packsize for TwinCAT3 = 0 or 8...and yes I've tested it already :ROFLMAO:

in .NET the TC3 application example would become:
Code:
using TwinCAT.Ads;
using System.Runtime.InteropServices; //For the marshaling stuff :)

namespace WindowsFormsApplication1
{
    [StructLayout(LayoutKind.Sequential, Pack = 8)]
    public struct St_recette
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        public String80[] Nom;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        St_CodeFonction[] Recette;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 8)]
    public struct String80
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 81)]
        public string String81;

    }    


    [StructLayout(LayoutKind.Sequential, Pack=8)]
    public struct St_CodeFonction
    {
        [MarshalAs(UnmanagedType.I1)]
        public Boolean bEnable;
        public Int16 Fonction;
        public UInt16 Code;
        public UInt32 Attente;
        public Single Position_Z;
        public Single Position_X;
        public Single Position_R;
        public Single Vitesse_ZXR;
        public Single Position_T;
        public Single Vitesse_T;
        public UInt32 Debit;
    }

    public partial class Form1 : Form
    {
        TcAdsClient tcClient = new TcAdsClient();
        St_recette dataToRead;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            tcClient.Connect(851);

            try
            {
                dataToRead = (St_recette)tcClient.ReadAny(tcClient.CreateVariableHandle("GVL.varTest"), typeof(St_recette));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}

packsize = 8 (or 0) own choice I guess if I read the msdn right :cool:
port would be 851 AND the global variables changed from being ".VarTest" to "GVL.VarTest"
-> I've added a global variables list named "GVL" to the project, so you must call the variable with it's fully qualified name...

So now I guess you have already enough routes to think about no?! :confused:

Have fun with it!!!

Greetz,
Peter
 
Zurück
Oben