Wiesemann & Theis GmbH

Netzwerk-, Sensor- & Schnittstellentechnik für Industrie, Office & IT

Tutorial zum Web-IO Digital:

Web-IO Digital mit
Visual Basic.Net über
Binary-Sockets ansprechen


Als Nachfolger von MS Visual Basic 5 und 6 gibt es inzwischen VB.Net in verschiedenen Versionen bis hin zu VB 2019. Auch die aktuelle Visual Basic Version bietet alles, was zum Programmieren von TCP/IP-Anwendungen nötig ist - sogar die Unterstützung binärer Strukturen. Damit ist Visual Basic bis heute ein beliebtes Hilfsmittel, um Anwendungen zu erstellen, die mit dem Web-IO Digital kommunizieren, zumal die Express Version von Visual Basic bei Microsoft kostenlos zum Download angeboten wird. Zusätzliche Treiber oder DLLs werden nicht benötigt.

Mit Visual Basic steuern

Mit dem folgenden Programmbeispiel können Sie Ihr Web-IO Digital mit seinen Inputs und Outputs mit einer Windows-Anwendung über den Binary-Socket-Modus ansprechen.


Vorbereitungen


Zusammenstellen der verschiedenen Bedienelemente und Anzeigeobjekte im VB.net-Form

Bedienelemente Visual Basic

Neben den hier gezeigten Objekten benötigt das Programm zusätzlich einen Timer für das Polling (timer_polling).

Bei der Benennung der einzelnen Objekte ist es hilfreich, sinngebende Namen zu verwenden. In diesem Beispiel beschreibt der erste Teil des Namens die Art des Objektes und der zweite Teil die Funktion.

Grundsätzliches

Während der Aufbau grafischer Benutzeroberfächen in Visual Basic Express genauso einfach zu bewerkstelligen ist wie mit den Vorgängerversionen, gestalten sich andere Aufgaben zunächst gewöhnungsbedürftig.

Für VB in der aktuellen Version steht nicht mehr das aus VB5 und VB6 bekannte Winsock-Steuerelement zur Verfügung.

Stattdessen muss für den Netzwerkzugriff über das Import-Statement der Namespace für die verwendeten Socket-Klassen im Kopf des Quelltextes instanziert werden. Darüber hinaus muss der Socket, auf dem die Kommunikation abgewickelt werden soll, angelegt werden und es muss ein Buffer für die Eingangsdaten definiert werden.

Ferner wurde die Kapselung einzelner Objekte in VB.Net soweit vorangetrieben, dass Objekte, die innerhalb eines Thread angelegt sind, den Zugriff aus einem anderen Thread heraus nicht zulassen. So kann z. B. eine Checkbox, die in Thread A angelegt wurde, aus Thread B nicht gesetzt werden.

Um dennoch Objekteigenschaften für andere Threads zugänglich zu machen, müssen im eigenen Thread Sub-Prozeduren zur Objektänderung angelegt werden. Zu diesen Sub-Prozeduren werden dann Delegate gebildet, über die andere Threads zugreifen können.

So z. B. auch um Steuerelemente des Formulars nach erfolgreichem Verbindungsaufbau zur Bedienung freizuschalten oder bei Verbindungsende zu sperren, aber auch um die Input/Output-Checkboxen nach Datenempfang an die tatsächlichen IO-Zustände anzupassen.

							
Imports System.Net.Sockets
Imports System.Net

Public Class Form1
  Public Structure IO_State
    Dim outputstate0 As Boolean
    Dim outputstate1 As Boolean
    Dim inputstate0 As Boolean
    Dim inputstate1 As Boolean
    Dim countervalue0 As Long
    Dim countervalue1 As Long
  End Structure

  Private Delegate Sub DelegateSub()
  Private connectenable As New DelegateSub(AddressOf connect_enable)
  Private disconnectenable As New DelegateSub(AddressOf disconnect_enable)
  Private formupdate As New DelegateSub(AddressOf form_update)
  Dim TCP_client As Socket
  Dim connection_ar As IAsyncResult
  Dim receivebuffer(511) As Byte
  Dim IOState As IO_State

  Private Sub connect_enable()
    bt_connect.Enabled = False
    gb_io.Enabled = True
    bt_disconnect.Enabled = True
    Timer_polling.Enabled = True
    ToolStripStatusLabel1.Text = "Connected to " + tb_ip.Text + " : " + tb_port.Text
  End Sub

  Private Sub disconnect_enable()
    bt_connect.Enabled = True
    gb_io.Enabled = False
    bt_disconnect.Enabled = False
    timer_polling.Enabled = False
    ToolStripStatusLabel1.Text = "No Connection"
  End Sub

  Private Sub form_update()
    If IOState.inputstate0 = True Then
      cb_input0.Checked = True
    Else
      cb_input0.Checked = False
    End If
    If IOState.inputstate1 = True Then
      cb_input1.Checked = True
    Else
      cb_input1.Checked = False
    End If
    If IOState.outputstate0 = True Then
      cb_output0.Checked = True
    Else
      cb_output0.Checked = False
    End If
    If IOState.outputstate1 = True Then
      cb_Output1.Checked = True
    Else
      cb_Output1.Checked = False
    End If
    tb_counter0.Text = IOState.countervalue0
    tb_counter1.Text = IOState.countervalue1
  End Sub
							
						

Die Binär-Strukturen

Für den Binary-Zugriff müssen die benötigten Binär-Strukturen definiert werden, über die mit dem Web-IO kommuniziert werden soll. Eine detaillierte Beschreibung dieser Strukturen finden Sie in der Binary-Kurzübersicht oder im Programmierhandbuch zum Web-IO.

Die Struktur EADriver
Mit ihren vier 16-Bit Variablen ist EADriver die Grundstruktur, die auch Bestandteil aller weiteren Strukturen ist.

							
Public Structure structEADriver
  Dim Start_1 As UInt16
  Dim Start_2 As UInt16
  Dim StructType As UInt16
  Dim StructLength As UInt16
End Structure

<StructLayout(LayoutKind.Explicit)> Public Structure structOptions
  <FieldOffset(0)> Dim EADriver As structEADriver
  <FieldOffset(8)> Dim Version As UInt32
  <FieldOffset(12)> Dim Options As UInt32
End Structure

Public Structure structSetBit
  Dim EADriver As structEADriver
  Dim Mask As UInt16
  Dim Value As UInt16
End Structure

Public Structure structReadCounter
  Dim EADriver As structEADriver
  Dim CounterIndex As UInt16
End Structure

Public Structure structWriteRegister
  Dim EADriver As structEADriver
  Dim Amount As UInt16
  Dim Value As UInt16
End Structure

Public Structure structRegisterState
  Dim EADriver As structEADriver
  Dim DriverID As UInt16
  Dim InputValue As UInt16
  Dim OutputValue As UInt16
End Structure

<StructLayout(LayoutKind.Explicit)> Public Structure structCounter
  <FieldOffset(0)> Dim EADriver As structEADriver
  <FieldOffset(8)> Dim CounterIndex As UInt16
  <FieldOffset(10)> Dim CounterValue As UInt32
End Structure

<StructLayout(LayoutKind.Explicit)> Public Structure structAllCounter
  <FieldOffset(0)> Dim EADriver As structEADriver
  <FieldOffset(8)> Dim CounterNoOf As UInt16
  <FieldOffset(10)> Dim CounterValue0 As UInt32
  <FieldOffset(14)> Dim CounterValue1 As UInt32
End Structure
							
						

Bei den Strukturen ist es wichtig, dass die Einzelvariablen bündig im Speicher hintereinander liegen. Das handhabt Visual Basic nicht automatisch so, insbesondere dann, wenn in einer Struktur Variablen unterschiedlicher Größe zusammengefasst sind. Um dennoch eine bündige Speicherbelegung zu gewährleisten, wird über <StructLayout(LayoutKind.Explicit)> festgelegt, dass jeder Einzelvariablen über <FieldOffset(14)> ein fester Offset zur ersten Speicherstelle der Struktur zugewiesen wird.

Verbindungskontrolle

Einleiten der Verbindung

Durch Eingabe der IP-Adresse des Web-IO in das Textfeld ed_ip und Klick auf den Button bt_connect, wird der Verbindungsaufbau gestartet.

							
  Private Sub bt_connect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_connect.Click
    Dim WebIOep As New IPEndPoint(IPAddress.Parse(tb_ip.Text), Val(tb_port.Text))
    If tb_ip.Text <> "" And tb_port.Text <> "" Then
      TCP_client = New Socket(AddressFamily.InterNetwork, SocketType.Stream, _ ProtocolType.Tcp)
      bt_connect.Enabled = False
      Try
        TCP_client.BeginConnect(WebIOep, New AsyncCallback(AddressOf callback_connect), TCP_client)
      Catch ex As Exception
      End Try
    End If
  End Sub
							
						

Verbindungsaufbau

Für die Abwicklung des TCP/IP-Handlings wird zunächst ein IPEndPoint aus IP-Adresse und TCP-Port definiert und damit der TCP_client Socket initialisiert. Im Zuge der Verbindungsanforderung wird ein Verweis auf eine Callback-Prozedur geschaffen.

Verbindung kommt zustande

Sobald das Web-IO die Verbindung annimmt, wird die Callback-Prozedur ausgeführt. Über Invoke wird das Delegat zur Prozedur aufgerufen, die die Steuerelemente freigibt und in der Statuszeile den Connect-Status anzeigt. Darüber hinaus wird ein Verweis auf eine Callback-Routine für den Datenempfang erstellt.

Über Senden der Struktur Options an das Web-IO wird dieses angewiesen, beim Setzen eines Outputs den veränderten Schaltzustand über die Struktur RegisterState zu übermitteln.

							
Private Sub callback_connect(ByVal ar As IAsyncResult)
  Invoke(connectenable)
  connection_ar = ar
  Try
    TCP_client.EndConnect(ar)
    TCP_client.BeginReceive(receivebuffer, 0, 512, SocketFlags.None, New AsyncCallback(AddressOf callback_readdata), TCP_client)
    Dim BufPtr As IntPtr
    Dim Options As structOptions
    Options.EADriver.Start_1 = 0
    Options.EADriver.Start_2 = 0
    Options.EADriver.StructType = &H1F0
    Options.EADriver.StructLength = 16
    Options.Version = 1
    Options.Options = 1
    BufPtr = Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(Options))
    Marshal.StructureToPtr(Options, BufPtr, True)
    sendstructure(BufPtr, Options.EADriver.StructLength)
  Catch ex As Exception
    closeconnections()
  End Try
End Sub
							
						

Trennen der Verbindung

Die Verbindung bleibt solange bestehen, bis sie vom Benutzer durch Klick auf den Disconnect-Button beendet wird oder das Web-IO die Verbindung beendet.

							  Private Sub bt_disconnect_Click(ByVal sender	As System.Object, ByVal e As System.EventArgs) Handles bt_disconnect.Click
    Invoke(disconnectenable)
    closeconnections()
  End Sub
							
						

In diesem Fall wird eine entsprechende Prozedur aufgerufen.

							  Private Sub closeconnections()
    Try
      TCP_client.EndReceive(connection_ar)
    Catch ex As Exception
    End Try
    Try
      TCP_client.Shutdown(SocketShutdown.Both)
    Catch ex As Exception
    End Try
    Try
      TCP_client.Close()
    Catch ex As Exception
    End Try
    Invoke(disconnectenable)
  End Sub
							
						

Verbindungsfehler

Alle die TCP/IP-Kommunikation betreffenden Aktionen werden innerhalb der Try-Anweisung ausgeführt. Treten Fehler auf, wird ebenfalls die CloseConnection-Prozedur aufgerufen.

Bedienung und Kommunikation von Client-Seite

Senden von Kommandos

Sobald eine Verbindung mit dem Web-IO zustande gekommen ist, kann der Anwender durch Bedienung der entsprechenden Programmelemente Binärstrukturen an das Web-IO senden.

							
Private Sub sendstructure(ByVal BufPtr As IntPtr, Bufsize As Integer)
  Dim senddata As Byte()
  ReDim senddata(Bufsize - 1)
  Marshal.Copy(BufPtr, senddata, 0, Bufsize)
  Try
    TCP_client.Send(senddata)
  Catch ex As Exception
    closeconnections()
  End Try
  Marshal.FreeHGlobal(BufPtr)
End Sub
							
						

Visual Basic sieht keine Methode zum direkten Versenden von Binärstrukturen vor. Binäre Daten können nur als ein Byte-Array gesendet werden. Deshalb wird beim Aufruf der sendstructure-Funktion ein Pointer (Zeiger) übergeben. Dieser Pointer verweist auf die Speicherstelle, ab der der Inhalt der zu versendenden Strukur zu finden ist. Hier wird deutlich, warum die Strukturvariablen Byte-bündig im Speicher liegen müssen. Als zweiter Parameter wird die Länge der Struktur übergeben.

Über Marshal.Copy(BufPtr, senddata, 0, Bufsize) werden die Strukturdaten dann in ein Byte-Array kopiert. Dieses Byte-Array wird dann an das Web-IO versendet.

Setzen der Outputs

Das Setzen der Outputs wird dem Anwender über zwei Checkboxen cb_outputx ermöglicht. Das Programm nutzt dazu das MouseUP-Ereignis dieses Objektes. Wird ein MouseUp, also ein Loslassen der Output-Checkbox, registriert, führt das Programm die entsprechende Prozedur aus und gibt - je nachdem, ob die Checkbox gesetzt ist oder nicht - die entsprechend ausgefüllte Set-Bit-Struktur an das Web-IO weiter.

							
Private Sub cb_output0_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles cb_output0.MouseUp
  Dim BufPtr As IntPtr
  Dim SetBit As structSetBit
  SetBit.EADriver.Start_1 = 0
  SetBit.EADriver.Start_2 = 0
  SetBit.EADriver.StructType = 9
  SetBit.EADriver.StructLength = 12
  SetBit.Mask = 1
  If cb_output0.Checked Then
    SetBit.Value = 1
  Else
    SetBit.Value = 0
  End If
  BufPtr = Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(SetBit))
  Marshal.StructureToPtr(SetBit, BufPtr, True)
  sendstructure(BufPtr, SetBit.EADriver.StructLength)
End Sub

Private Sub cb_Output1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles cb_Output1.MouseUp
  Dim BufPtr As IntPtr
  Dim SetBit As structSetBit
  SetBit.EADriver.Start_1 = 0
  SetBit.EADriver.Start_2 = 0
  SetBit.EADriver.StructType = 9
  SetBit.EADriver.StructLength = 12
  SetBit.Mask = 2
  If cb_Output1.Checked Then
    SetBit.Value = 2
  Else
    SetBit.Value = 0
  End If
  BufPtr = Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(SetBit))
  Marshal.StructureToPtr(SetBit, BufPtr, True)
  sendstructure(BufPtr, SetBit.EADriver.StructLength)
End Sub
							
						

Output/Input-Statusabfragen

Den Status der Outputs und Inputs kann der Anwender durch Anklicken des zugehörigen Buttons anfordern.

							
  Private Sub bt_outputs_read_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_outputs_read.Click
    Dim BufPtr As IntPtr
    Dim RegisterRequest As structEADriver
    RegisterRequest.Start_1 = 0
    RegisterRequest.Start_2 = 0
    RegisterRequest.StructType = &H21
    RegisterRequest.StructLength = 8
    BufPtr = Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(RegisterRequest))
    Marshal.StructureToPtr(RegisterRequest, BufPtr, True)
    sendstructure(BufPtr, RegisterRequest.StructLength)
  End Sub
							
						

Über Senden der Struktur RegisterRequest werden die Schaltzustände von Inputs und Outputs angefordert. Das Web-IO beantwortet diese Anfrage mit der Struktur RegisterState.

Sollen nur die Inputs abgefragt werden, wir das durch Klicken auf den bt_inputs-Button ausgelöst. Hierzu wird die Struktur ReadRegister versendet, was das Web-IO mit der Struktur WriteRegister beantwortet.

							
  Private Sub bt_inputs_read_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_inputs_read.Click
    Dim BufPtr As IntPtr
    Dim ReadRegister As structEADriver
    ReadRegister.Start_1 = 0
    ReadRegister.Start_2 = 0
    ReadRegister.StructType = 1
    ReadRegister.StructLength = 8
    BufPtr = Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(ReadRegister))
    Marshal.StructureToPtr(ReadRegister, BufPtr, True)
    sendstructure(BufPtr, ReadRegister.StructLength)
  End Sub
							
						

Counter abfragen/löschen

Auch die Zählerstände der Input-Counter lassen sich abfragen bzw. löschen. Dazu wird die Struktur ReadCounter bzw. ReadClearCounter versendet, wobei mit CounterIndex die Nummer des Counters übergeben wird. Das Web-IO antwortet mit der Struktur Counter.

							
  Private Sub bt_counter_read0_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_counter_read0.Click
    Dim BufPtr As IntPtr
    Dim ReadCounter As structReadCounter
    ReadCounter.EADriver.Start_1 = 0
    ReadCounter.EADriver.Start_2 = 0
    ReadCounter.EADriver.StructType = &HB0
    ReadCounter.EADriver.StructLength = 10
    ReadCounter.CounterIndex = 0
    BufPtr = Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(ReadCounter))
    Marshal.StructureToPtr(ReadCounter, BufPtr, True)
    sendstructure(BufPtr, ReadCounter.EADriver.StructLength)
  End Sub

  Private Sub bt_counter_read1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_counter_read0.Click
    Dim BufPtr As IntPtr
    Dim ReadCounter As structReadCounter
    ReadCounter.EADriver.Start_1 = 0
    ReadCounter.EADriver.Start_2 = 0
    ReadCounter.EADriver.StructType = &HB0
    ReadCounter.EADriver.StructLength = 10
    ReadCounter.CounterIndex = 1
    BufPtr = Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(ReadCounter))
    Marshal.StructureToPtr(ReadCounter, BufPtr, True)
    sendstructure(BufPtr, ReadCounter.EADriver.StructLength)
  End Sub

  Private Sub bt_counter_clear0_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_counter_clear0.Click
    Dim BufPtr As IntPtr
    Dim ReadClearCounter As structReadCounter
    ReadClearCounter.EADriver.Start_1 = 0
    ReadClearCounter.EADriver.Start_2 = 0
    ReadClearCounter.EADriver.StructType = &HC0
    ReadClearCounter.EADriver.StructLength = 10
    ReadClearCounter.CounterIndex = 0
    BufPtr = Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(ReadClearCounter))
    Marshal.StructureToPtr(ReadClearCounter, BufPtr, True)
    sendstructure(BufPtr, ReadClearCounter.EADriver.StructLength)
  End Sub

  Private Sub bt_counter_clear1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_counter_clear0.Click
    Dim BufPtr As IntPtr
    Dim ReadClearCounter As structReadCounter
    ReadClearCounter.EADriver.Start_1 = 0
    ReadClearCounter.EADriver.Start_2 = 0
    ReadClearCounter.EADriver.StructType = &HC0
    ReadClearCounter.EADriver.StructLength = 10
    ReadClearCounter.CounterIndex = 1
    BufPtr = Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(ReadClearCounter))
    Marshal.StructureToPtr(ReadClearCounter, BufPtr, True)
    sendstructure(BufPtr, ReadClearCounter.EADriver.StructLength)
  End Sub
							
						

Über die Struktur ReadAllCounter bzw. ReadAllCounter lassen sich auch alle Counter zeitgleich lesen bzw. löschen. Das Web-IO antwortet mit der Struktur AllCounter.

							
  Private Sub bt_counter_readall_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_counter_readall.Click
    Dim BufPtr As IntPtr
    Dim ReadAllCounter As structEADriver
    ReadAllCounter.Start_1 = 0
    ReadallCounter.Start_2 = 0
    ReadAllCounter.StructType = &HB1
    ReadAllCounter.StructLength = 10
    BufPtr = Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(ReadAllCounter))
    Marshal.StructureToPtr(ReadAllCounter, BufPtr, True)
    sendstructure(BufPtr, ReadAllCounter.StructLength)
  End Sub

  Private Sub bt_counter_clearall_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_counter_clearall.Click
    Dim BufPtr As IntPtr
    Dim ReadClaerAllCounter As structEADriver
    ReadClaerAllCounter.Start_1 = 0
    ReadClaerAllCounter.Start_2 = 0
    ReadClaerAllCounter.StructType = &HC1
    ReadClaerAllCounter.StructLength = 10
    BufPtr = Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(ReadClaerAllCounter))
    Marshal.StructureToPtr(ReadClaerAllCounter, BufPtr, True)
    sendstructure(BufPtr, ReadClaerAllCounter.StructLength)
  End Sub
							
						

Datenempfang vom Web-IO

Auswerten und Anzeigen der empfangenen Daten

Das Web-IO sendet je nach Anfrage oder auslösendem Ereignis die passende Struktur zurück. Bei Datenempfang wird die entsprechende Callback-Prozedur aufgerufen. Zur Auswertung befüllen die ersten 8 Byte des empfangenen Byte-Array über eine Zeigeroperation zunächst eine EADriver-Struktur. Um welchen Strukturtyp es sich handelt, erkennt die Anwendung über die Variable EADriver.StructType.

  • EADriver.StructType = 8
    Struktur WriteRegister für den Status der Inputs

  • EADriver.StructType = 31 (hex.)
    Struktur RegisterState für den Status der Inputs und Outputs

  • EADriver.StructType = B4 (hex.)
    Struktur Counter für den Wert einzelner Counter

  • EADriver.StructType = B5 (hex.)
    Struktur AllCounter für den Wert aller Counter

Zur Auswertung befüllt das empfangenen Byte-Array über eine Zeigeroperation nun die passende Struktur.

Die so übergebenen Werte werden dann ausgewertet und angezeigt. Für die Inputs und Outputs wird über WriteRegister.Value, RegisterStae.InputValue und RegisterStae.outputValue das Bitmuster aller Inputs bzw. Outputs übergeben.

							
Private Sub callback_readdata(ByVal ar As IAsyncResult)
  If TCP_client.Connected Then
    Dim bytesread As Integer
    Try
      bytesread = TCP_client.EndReceive(ar)
    Catch ex As Exception
    End Try
    If bytesread = 0 Then
      closeconnections()
    Else
      Try
        TCP_client.BeginReceive(receivebuffer, 0, 512, SocketFlags.None, New AsyncCallback(AddressOf callback_readdata), TCP_client)
      Catch ex As Exception
        closeconnections()
      End Try
      Dim MyGC As GCHandle = GCHandle.Alloc(receivebuffer, GCHandleType.Pinned)
      Dim EADriver As structEADriver = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, EADriver.GetType)

      Select Case EADriver.StructType
      Case 8
        Dim WriteRegister As structWriteRegister = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, WriteRegister.GetType)
        If (WriteRegister.Value And 1) = 1 Then
          IOState.inputstate0 = True
        Else
          IOState.inputstate0 = False
        End If
        If (WriteRegister.Value And 2) = 2 Then
          IOState.inputstate1 = True
        Else
          IOState.inputstate1 = False
        End If
      Case &H31
        Dim RegisterState As structRegisterState = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, RegisterState.GetType)
        If (RegisterState.InputValue And 1) = 1 Then
          IOState.inputstate0 = True
        Else
          IOState.inputstate0 = False
        End If
        If (RegisterState.InputValue And 2) = 2 Then
          IOState.inputstate1 = True
        Else
          IOState.inputstate1 = False
        End If
        If (RegisterState.OutputValue And 1) = 1 Then
          IOState.outputstate0 = True
        Else
          IOState.outputstate0 = False
        End If
        If (RegisterState.OutputValue And 2) = 2 Then
          IOState.outputstate1 = True
        Else
          IOState.outputstate1 = False
        End If
      Case &HB4
        Dim Counter As structCounter = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, Counter.GetType)
        If Counter.CounterIndex = 0 Then IOState.countervalue0 = Counter.CounterValue.ToString
        If Counter.CounterIndex = 1 Then IOState.countervalue1 = Counter.CounterValue.ToString
      Case &HB5
        Dim AllCounter As structAllCounter = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, AllCounter.GetType)
        IOState.countervalue0 = AllCounter.CounterValue0.ToString
        IOState.countervalue1 = AllCounter.CounterValue1.ToString
      End Select
      Invoke(formupdate)
      MyGC.Free()
    End If
  End If
End Sub
							
						

Polling

Zyklisches Abfragen bestimmter Werte

Um auch eine automatische Aktualisierung der Anzeige zu ermöglichen, wird ein Timer benutzt.

In Abhängigkeit der Checkboxen für Output-, Input- und Counter-Polling werden die entsprechenden Informationen im eingestellten Intervall vom Web-IO abgerufen.

							
  Private Sub timer_polling_Elapsed(ByVal sender As System.Object, ByVal e As System.Timers.ElapsedEventArgs) Handles timer_polling.Elapsed
    If ((cb_input_polling.Checked Or cb_output_polling.Checked) And TCP_client.Connected) Then
      Dim BufPtr As IntPtr
      Dim RegisterRequest As structEADriver
      RegisterRequest.Start_1 = 0
      RegisterRequest.Start_2 = 0
      RegisterRequest.StructType = 1
      RegisterRequest.StructLength = &H21
      BufPtr = Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(RegisterRequest))
      Marshal.StructureToPtr(RegisterRequest, BufPtr, True)
      sendstructure(BufPtr, RegisterRequest.StructLength)
    End If
    If (cb_counter_polling.Checked And TCP_client.Connected) Then
      Dim BufPtr As IntPtr
      Dim ReadAllCounter As structEADriver
      ReadAllCounter.Start_1 = 0
      ReadAllCounter.Start_2 = 0
      ReadAllCounter.StructType = &HB1
      ReadAllCounter.StructLength = 10
      BufPtr = Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(ReadAllCounter))
      Marshal.StructureToPtr(ReadAllCounter, BufPtr, True)
      sendstructure(BufPtr, ReadAllCounter.StructLength)
    End If
  End Sub
							
						

Das gewünschte Intervall kann in das entsprechende Textfeld eingegeben werden. Bei Änderung wird das Timer-Intervall dann automatisch angepasst.

							
  Private Sub tb_interval_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb_interval.TextChanged
    timer_polling.Interval = Val(tb_interval.Text)
  End Sub
							
						

Das Beispiel-Programm unterstützt alle gängigen Funktionen des Web-IO im Binary-Socket-Modus, optimiert für das Web-IO 2x Digital Input, 2x Digital Output. Für die anderen Web-IO-Modelle müssen ggf. Anpassungen am Programm vorgenommen werden. Eine detaillierte Beschreibung zu den Binärstrukturen finden Sie in der Binary-Kurzübersicht oder im Programmierhandbuch zum Web-IO.

Programmbeispiel herunterladen


Produkte



^