W&T collega
Adattatori per TCP/IP, Ethernet, RS-232, RS-485, USB, 20 mA, Fibra ottica di vetro e plastica, http, SNMP, OPC, Modbus TCP, I/O digitale, I/O analogico, ISA, PCI

Tutorial al Web-IO digitale:

Attivare il Web-IO digitale con C# mediante
socket binari


Per la creazione di applicazioni Windows, Visual C++ è stata una delle piattaforme di sviluppo più utilizzate fino a poco tempo fa. Nel frattempo sempre più programmatori lavorano con il framework .Net e creano le loro applicazioni in C# (C Sharp).

Controllo di Web-IO con C Sharp

Con il seguente esempio di programma C# l’utente può attivare il Web-IO digitale con i suoi input e output in un’applicazione Windows attraverso la modalità socket binario.


Preparativi


Collocazione dei diversi elementi di comando e oggetti di visualizzazione nel modulo VB.net

Elementi di comando Visual Basic

Nella denominazione dei singoli oggetti è utile utilizzare nomi che ne riprendono il significato. In questo esempio la prima parte del nome descrive il tipo dell’oggetto e la seconda parte la funzione.

Importazione di risorse e dichiarazione di variabili locali

Come prima cosa vengono importate tutte le classi necessarie per il collegamento di rete e la GUI (Graphical User Interface).


using System;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Runtime.InteropServices;
            

Successivamente i componenti dell’applicazione e le variabili importanti per un collegamento TCP vengono dichiarati variabili locali della classe e con ciò resi accessibili ai metodi della classe.


  public class mainWindow : System.Windows.Forms.Form
  {	// All elements of the application
    private CheckBox cb_Output0;
    private CheckBox cb_Output1;
    private CheckBox cb_Input0;
    private CheckBox cb_Input1;
    private CheckBox cb_Polling_Counter;
    private CheckBox cb_Polling_Outputs;
    private CheckBox cb_Polling_Inputs;
    private Button bt_Readall_Outputs;
    private Button bt_Readall_Inputs;
    private Button bt_Clear_Counter0;
    private Button bt_Clear_Counter1;
    private Button bt_Clearall_Counter;
    private Button bt_Read_Counter0;
    private Button bt_Read_Counter1;
    private Button bt_Readall_Counter;
    private Label lb_Counter0;
    private Label lb_Counter1;
    private Label lb_Intervall;
    private TextBox tb_Counter0;
    private TextBox tb_Counter1;
    private TextBox tb_Intervall;
    private Button bt_Connect;
    private Button bt_Disconnect;
    private TextBox tb_Password;
    private TextBox tb_Port;
    private TextBox tb_IP;
    private GroupBox gb_ioControlBox;
    private GroupBox gb_conControlBox;
    private StatusBar statusBar;
    private Label label2;
    private Label label1;
    private Label label3;
    private System.Windows.Forms.Timer counter;
    private System.Windows.Forms.Timer outputs;
    private System.Windows.Forms.Timer inputs;

    private Socket client;
    private int intervall;
    private byte[] receivebuffer = new byte[256];
    private structIOState IOState;
    delegate void delegateSub();
						

Le strutture binarie

Per l’accesso binario è necessario definire le necessarie strutture binarie, con cui si deve comunicare con il Web-IO. Una descrizione dettagliata di queste strutture è disponibile nella breve panoramica binary o nel manuale di programmazione sul Web-IO.

La struttura IOState

La struttura IOState non rientra nelle strutture binarie e non viene impiegata direttamente per la comunicazione tra applicazione e Web-IO. Serve per lo scambio degli stati IO tra thread ricevente e le parti di programma, deputate all’aggiornamento degli elementi di visualizzazione.

La struttura EADriver

Con le sue quattro variabili a 16 bit è EADriver la struttura di base che è anche un elemento di tutte le altre strutture binarie.


public struct structIOState
{
  public UInt16 InputState;
  public UInt16 OutputState;
  public UInt32 CounterValue0;
  public UInt32 CounterValue1;
}

public struct structEADriver
{
  public UInt16 Start_1;
  public UInt16 Start_2;
  public UInt16 StructType;
  public UInt16 StructLength;
}

public struct structOptions
{
  public structEADriver EADriver;
  public UInt32 Version;
  public UInt32 Options;
}

public struct structWriteRegister
{
  public structEADriver EADriver;
  public UInt16 Amount;
  public UInt16 Value;
}

public struct structSetBit
{
  public structEADriver EADriver;
  public UInt16 Mask;
  public UInt16 Value;
}

public struct structRegisterState
{
  public structEADriver EADriver;
  public UInt16 DriverID;
  public UInt16 InputValue;
  public UInt16 OutputValue;
}

public struct structReadCounter
{
  public structEADriver EADriver;
  public UInt16 CounterIndex;
}

[StructLayout(LayoutKind.Explicit)]
public struct structCounter
{
  [FieldOffset(0)]public structEADriver EADriver;
  [FieldOffset(8)] public UInt16 CounterIndex;
  [FieldOffset(10)] public UInt32 CounterValue;
}

[StructLayout(LayoutKind.Explicit)]
public struct structAllCounter
{
  [FieldOffset(0)] public structEADriver EADriver;
  [FieldOffset(8)] public UInt16 CounterNoOf;
  [FieldOffset(10)] public UInt32 CounterValue0;
  [FieldOffset(14)] public UInt32 CounterValue1;
}
						

Nelle strutture è importante che le singole variabili vengano archiviate ininterrotte nella memoria. C# non realizza ciò automaticamente, in particolare se in una struttura vengono riunite variabili di dimensioni diverse. Per garantire tuttavia un’occupazione ininterrotta della memoria, si [StructLayout(LayoutKind.Explicit)] definisce che ogni singola variabile [FieldOffset(14)] viene assegnata mediante un offset fisso alla prima posizione della memoria della struttura.

Avvio del programma

Inizializzazione degli elementi di comando

Il gruppo con gli elementi di comando per il Web-IO viene innanzitutto bloccato per l’uso. Non appena viene realizzato un collegamento, vengono abilitati tutti gli elementi per i quali ha senso l’abilitazione.

Il nome del relativo elemento di comando può essere derivato in base al contesto dall’elemento stesso. I primi due caratteri del nome indicano il tipo dell’elemento (cb -> checkbox, bt -> button, gb -> groupbox e tb -> textbox).


public mainWindow()
{
  InitializeComponent();
  gb_ioControlBox.Enabled = false;
  bt_Disconnect.Enabled = false;
  cb_Input0.Enabled = false;
  cb_Input1.Enabled = false;
  tb_Counter0.Enabled = false;
  tb_Counter1.Enabled = false;
  IOState.InputState = 0;
  IOState.OutputState = 0;
  IOState.CounterValue0 = 0;
  IOState.CounterValue1 = 0;
}
						

Controllo del collegamento

Inizializzazione del collegamento

Immettendo l’indirizzo IP del Web-IO nel campo di testo ed_ip e facendo clic sul pulsante bt_connect viene avviata la creazione del collegamento.


private void bt_Connect_Click(object sender, System.EventArgs e)
{
  try
  {
    if ((tb_IP.Text != "") && (tb_Port.Text != ""))
    {
      client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(tb_IP.Text), int.Parse(tb_Port.Text));
      client.BeginConnect(ipep, new AsyncCallback(connectCallback), client);
    }
    else
      statusBar.Text = "IP and Port needed!";
  }
  catch (SocketException)
  {
    statusBar.Text = "Connection not possible!";
  }
}
						

Creazione del collegamento

Per lo svolgimento della gestione TCP/IP viene innanzitutto definito un IPEndPoint dall’indirizzo IP e dalla porta TCP e con ciò viene inizializzato il socket TCP_client. Durante la richiesta di collegamento viene creato un rimando a una procedura di callback.

Collegamento realizzato

Non appena il Web-IO accetta il collegamento, viene eseguita la procedura di callback. Inoltre viene creato un rimando a una routine di callback per la ricezione dei dati.

Inviando la struttura Options Al Web-IO questo viene istruito, fissando un output a trasmettere lo stato di attivazione modificato attraverso la struttura RegisterState.


private void connectCallback(IAsyncResult ar)
{
  try
  {
    client = (Socket)ar.AsyncState;
    client.EndConnect(ar);
    connectupdatedisplay();
    intervall = 1000;
    client.BeginReceive(receivebuffer, 0, 255, SocketFlags.None, new AsyncCallback(receiveCallback), client);
  }
  catch (Exception)
  {
    disconnect();
  }
  if (client.Connected)
  {
    IntPtr BufPtr;
    structOptions Options;
    Options.EADriver.Start_1 = 0;
    Options.EADriver.Start_2 = 0;
    Options.EADriver.StructType = 0x1F0;
    Options.EADriver.StructLength = 16;
    Options.Version = 0;
    Options.Options = 1;
    BufPtr = Marshal.AllocHGlobal(Marshal.SizeOf(Options));
    Marshal.StructureToPtr(Options, BufPtr, true);
    sendstructure(BufPtr, (short)Options.EADriver.StructLength);
  }
}
						

Inoltre avviando la procedura connectupdatedisplay() vengono autorizzati tutti gli elementi di comando necessari dell’applicazione e viene disattivato il Connect Button.


 private void connectupdatedisplay()
{
  if (InvokeRequired)
  {
    BeginInvoke(new delegateSub(connectupdatedisplay), new object[] { });
    return;
  }
  statusBar.Text = "Connected!";
  gb_ioControlBox.Enabled = true;
  bt_Disconnect.Enabled = true;
  bt_Connect.Enabled = false;
}
						

Nella versione attuale di C# non è più consentito accedere da un thread (qui la funzione Callback) a elementi grafici di un altro thread (forma).

Qui offre una soluzione l’uso di delegate e invoke.

Disinserzione del collegamento

Il collegamento sussiste finché viene interrotto dall’utente mediante clic sul tasto Disconnect o finché il Web-IO interrompe il collegamento.


private void bt_Disconnect_Click(object sender, System.EventArgs e)
{
  try
  {
    client.Shutdown(SocketShutdown.Both);
    client.Close();
    disconnectupdatedisplay();
  }
  catch (Exception)
  {
    statusBar.Text = "Not able to disconnect!";
  }
}
            

In questo caso viene richiamata una corrispondente procedura.


private void disconnect()
{
  try
  {
    client.Shutdown(SocketShutdown.Both);
    client.Close();
    disconnectupdatedisplay();
  }
  catch (Exception)
  {
    statusBar.Text = "Not able to disconnect!";
  }
}
            

Per un accesso sicuro in termini di thread il ripristino degli elementi del modulo è stato trasferito alla procedura disconnectupdatedisplay().


private void disconnectupdatedisplay()
{
  if (InvokeRequired)
  {
    BeginInvoke(new delegateSub(disconnectupdatedisplay), new object[] { });
    return;
  }
  statusBar.Text = "Disconnected!";
  gb_ioControlBox.Enabled = false;
  bt_Disconnect.Enabled = false;
  bt_Connect.Enabled = true;
}
            

Errore di collegamento

Tutte le azioni che riguardano la comunicazione TCP/IP vengono eseguite nell’ambito dell’istruzione Try. Se si verificano degli errori, viene utilizzato il disconnect(); metodo dell’ oggetto client.

Utilizzo e comunicazione della parte client

Invio di strutture binarie

Non appena viene realizzato un collegamento con il Web-IO, l’utente può inviare strutture binarie al Web-IO controllando i corrispondenti elementi del programma.


private void sendstructure(IntPtr BufPtr, Int16 BufSize)
{
  byte[] senddata;
  senddata = new byte[BufSize];
  Marshal.Copy(BufPtr, senddata, 0, BufSize);
  client.BeginSend(senddata, 0, senddata.Length, 0, new AsyncCallback(sendCallback), client);
}

private void sendCallback(IAsyncResult ar)
{
  try
  {
    Socket tmp_client = (Socket) ar.AsyncState;
    int bytessend = tmp_client.EndSend(ar);
  }
  catch(Exception)
  {
    statusBar.Text = "Error by sending";
  }
}
            

C# non prevede alcun metodo per l’invio diretto di strutture binarie. I dati binari possono essere inviati solo come byte array. Per questo all’apertura della funzione sendstructure viene trasmesso un pointer (indicatore). Il suddetto pointer rimanda al punto della memoria da cui è ritrovabile il contenuto della struttura da inviare. Qui è chiaro perché le variabili strutturali devono essere salvate nella memoria in byte ininterrotti. Come secondo parametro viene trasmessa la lunghezza della struttura.

Mediante Marshal.Copy(BufPtr, senddata, 0, Bufsize) i dati strutturali vengono poi copiati in una serie di byte (byte array). Questa serie di byte viene poi inviata al Web-IO.

Impostazione degli output

L’impostazione degli output è resa possibile all’utente da due caselle di spunta cb_outputx. Il programma utilizza a tal scopo l’evento MouseUP di questo oggetto. Se si registra un MouseUP, quindi rilasciando il checkbox output, il programma esegue la rispettiva procedura e trasmette, a seconda che il checkbox sia stato impostato o meno, la struttura SetBit opportunamente compilata al Web-IO.


private void cb_Output0_MouseUp(object sender, MouseEventArgs e)
{
  IntPtr BufPtr;
  structSetBit SetBit;
  SetBit.EADriver.Start_1 = 0;
  SetBit.EADriver.Start_2 = 0;
  SetBit.EADriver.StructType = 0x9;
  SetBit.EADriver.StructLength = 0xC;
  SetBit.Mask = 1;
  if (cb_Output0.Checked)
    SetBit.Value = 1;
  else
    SetBit.Value = 0;
  BufPtr = Marshal.AllocHGlobal(Marshal.SizeOf(SetBit));
  Marshal.StructureToPtr(SetBit, BufPtr, true);
  sendstructure(BufPtr, (short)SetBit.EADriver.StructLength);
}

private void cb_Output1_MouseUp(object sender, MouseEventArgs e)
{
  IntPtr BufPtr;
  structSetBit SetBit;
  SetBit.EADriver.Start_1 = 0;
  SetBit.EADriver.Start_2 = 0;
  SetBit.EADriver.StructType = 0x9;
  SetBit.EADriver.StructLength = 0xC;
  SetBit.Mask = 2;
  if (cb_Output1.Checked)
    SetBit.Value = 2;
  else
    SetBit.Value = 0;
  BufPtr = Marshal.AllocHGlobal(Marshal.SizeOf(SetBit));
  Marshal.StructureToPtr(SetBit, BufPtr, true);
  sendstructure(BufPtr, (short)SetBit.EADriver.StructLength);
}
            

Interrogazione dello stato degli output/input

L’utente può richiedere lo stato degli output e degli input facendo clic sul relativo pulsante.


private void bt_Readall_Outputs_Click(object sender, System.EventArgs e)
{
  IntPtr BufPtr;
  structEADriver RegisterRequest;
  RegisterRequest.Start_1 = 0;
  RegisterRequest.Start_2 = 0;
  RegisterRequest.StructType = 0x21;
  RegisterRequest.StructLength = 8;
  BufPtr = Marshal.AllocHGlobal(Marshal.SizeOf(RegisterRequest));
  Marshal.StructureToPtr(RegisterRequest, BufPtr, true);
  sendstructure(BufPtr, (short)RegisterRequest.StructLength);
}
            

Inviando la struttura RegisterRequest Vengono richiesti gli stati di attivazione di input e output. Il Web-IO risponde a questa richiesta con la struttura RegisterState.

Se fossero interrogati solo gli input, ciò viene avviato attraverso clic sul tasto bt_inputs. A tal scopo viene inviata la struttura ReadRegister a cui il Web-IO risponde con la struttura WriteRegister.


private void bt_Readall_Inputs_Click(object sender, System.EventArgs e)
{
  IntPtr BufPtr;
  structEADriver ReadRegister;
  ReadRegister.Start_1 = 0;
  ReadRegister.Start_2 = 0;
  ReadRegister.StructType = 1;
  ReadRegister.StructLength = 8;
  BufPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ReadRegister));
  Marshal.StructureToPtr(ReadRegister, BufPtr, true);
  sendstructure(BufPtr, (short)ReadRegister.StructLength);
}
            

Interrogazione/cancellazione dei counter

È possibile interrogare o cancellare anche gli stati dei counter degli input. A tal scopo viene inviata la struttura ReadCounter o ReadClearCounter, laddove con CounterIndex viene trasmesso il numero del counter. Il Web-IO risponde con la struttura Counter.


private void bt_Read_Counter0_Click(object sender, System.EventArgs e)
{
  IntPtr BufPtr;
  structReadCounter ReadCounter;
  ReadCounter.EADriver.Start_1 = 0;
  ReadCounter.EADriver.Start_2 = 0;
  ReadCounter.EADriver.StructType = 0xB0;
  ReadCounter.EADriver.StructLength = 0xA;
  ReadCounter.CounterIndex = 0;
  BufPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ReadCounter));
  Marshal.StructureToPtr(ReadCounter, BufPtr, true);
  sendstructure(BufPtr, (short)ReadCounter.EADriver.StructLength);
}

private void bt_Read_Counter1_Click(object sender, System.EventArgs e)
{
  IntPtr BufPtr;
  structReadCounter ReadCounter;
  ReadCounter.EADriver.Start_1 = 0;
  ReadCounter.EADriver.Start_2 = 0;
  ReadCounter.EADriver.StructType = 0xB0;
  ReadCounter.EADriver.StructLength = 0xA;
  ReadCounter.CounterIndex = 1;
  BufPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ReadCounter));
  Marshal.StructureToPtr(ReadCounter, BufPtr, true);
  sendstructure(BufPtr, (short)ReadCounter.EADriver.StructLength);
}

private void bt_Clear_Counter0_Click(object sender, System.EventArgs e)
{
  IntPtr BufPtr;
  structReadCounter ReadCounter;
  ReadCounter.EADriver.Start_1 = 0;
  ReadCounter.EADriver.Start_2 = 0;
  ReadCounter.EADriver.StructType = 0xC0;
  ReadCounter.EADriver.StructLength = 0xA;
  ReadCounter.CounterIndex = 0;
  BufPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ReadCounter));
  Marshal.StructureToPtr(ReadCounter, BufPtr, true);
  sendstructure(BufPtr, (short)ReadCounter.EADriver.StructLength);
}

private void bt_Clear_Counter1_Click(object sender, System.EventArgs e)
{
  IntPtr BufPtr;
  structReadCounter ReadCounter;
  ReadCounter.EADriver.Start_1 = 0;
  ReadCounter.EADriver.Start_2 = 0;
  ReadCounter.EADriver.StructType = 0xC0;
  ReadCounter.EADriver.StructLength = 0xA;
  ReadCounter.CounterIndex = 1;
  BufPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ReadCounter));
  Marshal.StructureToPtr(ReadCounter, BufPtr, true);
  sendstructure(BufPtr, (short)ReadCounter.EADriver.StructLength);
}
						

Sulla struttura ReadAllCounter o ReadClearAllCounter è possibile leggere o cancellare contemporaneamente anche tutti i counter. Il Web-IO risponde con la struttura AllCounter.


private void bt_Readall_Counter_Click(object sender, System.EventArgs e)
{
  IntPtr BufPtr;
  structEADriver ReadAllCounter;
  ReadAllCounter.Start_1 = 0;
  ReadAllCounter.Start_2 = 0;
  ReadAllCounter.StructType = 0xB1;
  ReadAllCounter.StructLength = 8;
  BufPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ReadAllCounter));
  Marshal.StructureToPtr(ReadAllCounter, BufPtr, true);
  sendstructure(BufPtr, (short)ReadAllCounter.StructLength);
}

private void bt_Clearall_Counter_Click(object sender, System.EventArgs e)
{
  IntPtr BufPtr;
  structEADriver ReadClearAllCounter;
  ReadClearAllCounter.Start_1 = 0;
  ReadClearAllCounter.Start_2 = 0;
  ReadClearAllCounter.StructType = 0xC1;
  ReadClearAllCounter.StructLength = 8;
  BufPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ReadClearAllCounter));
  Marshal.StructureToPtr(ReadClearAllCounter, BufPtr, true);
  sendstructure(BufPtr, (short)ReadClearAllCounter.StructLength);
}
						

Ricezione dei dati dal Web-IO

Analisi e visualizzazione dei dati ricevuti

Il Web-IO invia a seconda della richiesta o dell’evento da scatenare la struttura giusta. Alla ricezione dei dati viene aperta la corrispondente procedura di callback. Per la valutazione i primi 8 byte del byte-array ricevuto riempiono attraverso un’operazione del puntatore innanzitutto una struttura EADriver. L’applicazione riconosce di che tipo di struttura si tratta attraverso la variabile EADriver.StructType.

  • EADriver.StructType = 8
    Struttura WriteRegister per lo stato degli input

  • EADriver.StructType = 31 (hex.)
    Struttura RegisterState per lo stato degli input e output

  • EADriver.StructType = B4 (hex.)
    Struttura Counter per il valore di singoli counter

  • EADriver.StructType = B5 (hex.)
    Struttura AllCounter per il valore di tutti i counter

Per la valutazione il byte array ricevuto riempie ora la struttura adatta attraverso un’operazione del puntatore.

I valori così trasmessi vengono poi valutati e visualizzati. Per gli input e output viene trasmesso attraverso WriteRegister.Value, RegisterStae.InputValue e RegisterStae.outputValue lo schema di bit di tutti gli input e output.


private void receiveCallback(IAsyncResult ar)
{
  int BytesRead;
  string rcv = string.Empty;
  try
  {
    BytesRead = client.EndReceive(ar);
    client.BeginReceive(receivebuffer, 0, 255, SocketFlags.None, new AsyncCallback(receiveCallback), client);
  }
  catch (Exception)
  {
    BytesRead = 0;
  }
  if (BytesRead == 0)
  {
    if (client.Connected) { disconnect(); }
  }
  else
  {
    GCHandle MyGC = GCHandle.Alloc(receivebuffer, GCHandleType.Pinned);
    structEADriver EADriver = (structEADriver)Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), typeof(structEADriver));
    switch (EADriver.StructType)
    {
      case 8:
        structWriteRegister WriteRegister = (structWriteRegister)Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), typeof(structWriteRegister));
        IOState.InputState = WriteRegister.Value;
      break;
      case 0x31:
        structRegisterState RegisterState = (structRegisterState)Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), typeof(structRegisterState));
        IOState.InputState = RegisterState.InputValue;
        IOState.OutputState = RegisterState.OutputValue;
      break;
      case 0xB4:
        structCounter Counter = (structCounter)Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), typeof(structCounter));
        if (Counter.CounterIndex == 0) { IOState.CounterValue0 = Counter.CounterValue; }
        if (Counter.CounterIndex == 1) { IOState.CounterValue1 = Counter.CounterValue; }
      break;
      case 0xB5:
        structAllCounter AllCounter = (structAllCounter)Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), typeof(structAllCounter));
        IOState.CounterValue0 = AllCounter.CounterValue0;
        IOState.CounterValue1 = AllCounter.CounterValue1;
      break;
    }
    IOupdatedisplay();
    MyGC.Free();
  }
}
						

Per un aggiornamento della visualizzazione sicuro in termini di thread la copia del processo degli IO viene trasmesso attraverso la struttura IOState alla procedura IOupdatedisplay. Attraverso Invoke e formazione di Delegate gli elementi di visualizzazione interessati vengono adattati allo stato IO.


private void IOupdatedisplay()
{
  if (InvokeRequired)
  {
    BeginInvoke(new delegateSub(IOupdatedisplay), new object[] { });
    return;
  }
  if ((IOState.OutputState & 1) == 1)
    cb_Output0.Checked = true;
  else
    cb_Output0.Checked = false;
  if ((IOState.OutputState & 2) == 2)
    cb_Output1.Checked = true;
  else
    cb_Output1.Checked = false;
  if ((IOState.InputState & 1) == 1)
    cb_Input0.Checked = true;
  else
    cb_Input0.Checked = false;
  if ((IOState.InputState & 2) == 2)
    cb_Input1.Checked = true;
  else
    cb_Input1.Checked = false;
    tb_Counter0.Text = IOState.CounterValue0.ToString();
    tb_Counter1.Text = IOState.CounterValue1.ToString();
}
            

Polling

Interrogazione ciclica di determinati valori

Per permettere anche un aggiornamento automatico della visualizzazione, viene utilizzato un timer.

In base alle caselle di spunta per il polling degli output, degli input e dei counter le corrispondenti informazioni vengono interrogate dal Web-IO nell’intervallo impostato.


private void timer_handler(object sender, System.EventArgs e)
{
  if (sender == counter) bt_Readall_Counter_Click(sender, e);
  if (sender == outputs) bt_Readall_Outputs_Click(sender, e);
  if (sender == inputs) bt_Readall_Inputs_Click(sender, e);
}

private void cb_Polling_Counter_CheckedChanged(object sender, System.EventArgs e)
{
  if(cb_Polling_Counter.Checked)
  {
    counter = new System.Windows.Forms.Timer();
    counter.Interval = intervall;
    counter.Start();
    counter.Tick += new EventHandler(timer_handler);
  }
 else
   counter.Stop();
}

private void cb_Polling_Outputs_CheckedChanged(object sender, System.EventArgs e)
{
  if(cb_Polling_Outputs.Checked)
  {
    outputs = new System.Windows.Forms.Timer();
    outputs.Interval = intervall;
    outputs.Start();
    outputs.Tick += new EventHandler(timer_handler);
  }
  else
    outputs.Stop();
}

private void cb_Polling_Inputs_CheckedChanged(object sender, System.EventArgs e)
{
  if(cb_Polling_Inputs.Checked)
  {
    inputs = new System.Windows.Forms.Timer();
    inputs.Interval = intervall;
    inputs.Start();
    inputs.Tick += new EventHandler(timer_handler);
  }
  else
    inputs.Stop();
}
            

L’intervallo desiderato può essere immesso nel corrispondente campo di testo. In caso di una modifica l’intervallo del timer viene adattato automaticamente.


private void tb_Intervall_TextChanged(object sender, System.EventArgs e)
{
  try
  {
    if(Convert.ToInt32(tb_Intervall.Text) > 0)
    {
      intervall = Convert.ToInt32(tb_Intervall.Text);
      statusBar.Text = "New range: " + intervall.ToString() + " ms!";
    }
    else
      statusBar.Text = "Only positiv Integer allowed!";
  }
  catch(Exception)
  {
    statusBar.Text = "Only positiv Integer allowed!";
  }
}
						

Il programma esempio supporta tutte le comuni funzioni del Web-IO nella modalità socket binario ottimizzata per il Web-IO 2x input digitale, 2x output digitale. Per gli altri modelli di Web-IO devono eventualmente essere eseguiti adattamenti al programma. Una descrizione dettagliata delle strutture binarie è disponibile nella breve panoramica binary o nel manuale di programmazione sul Web-IO.

Download esempio di programma


Prodotti