W&T conecta
Interfaces para TCP/IP, Ethernet, RS-232, RS-485, USB, 20mA, fibra óptica de vidrio y de plástico, http, SNMP, OPC, Modbus TCP, I/O digital, I/O analógico, ISA, PCI

Tutorial al Web-IO digital:

Activar Web-IO Digital con C# vía
sockets binarios


Para la creación de aplicaciones Windows, Visual C++ ha sido hasta hace poco una de las plataformas de desarrollo más utilizadas. Entre tanto trabajan cada vez más programadores con el .Net Framework y crean sus aplicaciones en C# (C Sharp).

Dirigir Web-IO con C Sharp

Con el siguiente ejemplo de programa C#, usted puede activar su Web-IO Digital, con sus entradas y salidas, en una aplicación de Windows a través del modo de socket binario.


Preparativos


Recopilación de los diferentes elementos de manejo y objetos de visualización en formulario VB.net

Elementos de manejo Visual Basic

Al denominar cada uno de los objetos, es de gran ayuda usar nombres con sentido. En este ejemplo la primera parte del nombre describe la clase de objeto y la segunda la función.

Importar recursos y declaración de variables de miembros

En primer lugar se importan todas las clases necesarias para la conexión de red y 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;
            

A continuación se declaran los componentes de la aplicación y las variables importantes para una conexión TCP como variables de miembros de la clase, teniendo acceso así a los métodos de la clase.


  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();
						

Las estructuras binarias

Para el acceso binario es imprescindible definir las estructuras binarias requeridas con las que deba tener lugar la comunicación con el Web-IO. Encontrará una descripción detallada de esas estructuras en el breve resumen de estructuras binarias o en manual de programación para Web-IO.

La estructura IOState

La estructura IOState no forma parte de las estructuras binarias y no es imprescindible para la comunicación entre la aplicación y el Web-IO. Sirve para el intercambio de los estados de las EA entre el thread receptor y las partes del programa responsables de la actualización de los elementos presentados.

La estructura EADriver

Con sus cuatro variables de 16 bits EADriver es la estructura básica que también forma parte de todas las demás estructuras binarias.


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;
}
						

En las estructuras es importante que las distintas variables se encuentren agrupadas sucesivamente en la memoria. C# no lo maneja así automáticamente, especialmente cuando una estructura agrupa variables de diferentes tamaños. Aun así, para garantizar una ocupación agrupada de la memoria se determina mediante [StructLayout(LayoutKind.Explicit)] que se asigne cada variable individual a través de [FieldOffset(14)] un offset fijo para el primer puesto de la memoria de la estructura.

Arranque de programa

Instalar los elementos de manejo

El grupo con los elementos de manejo para el Web-IO se bloquea primero para el manejo. Tan pronto como se establezca una conexión, se da línea libre a todos los elementos, que poseen una versión conveniente.

El nombre del elemento respectivo de manejo se deriva del elemento mismo según el contexto. Los dos primeros signos del nombre significan el tipo del elemento (cb -> Checkbox, bt -> Button, gb -> Groupbox y 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;
}
						

El control de conexión

Introducir la conexión

La conexión se arranca entrando la dirección IP del Web-IO en el campo de texto ed_ip y chasqueando el botón bt_connect.


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!";
  }
}
						

La conexión

Para la tramitación del manejo TCP/IP se define primero un IPEndPoint de la dirección IP y puerto TCP y así inicializar el zócalo TCP_client. En el transcurso de la solicitud de conexión se crea una referencia a un procedimiento Callback.

Se establece la conexión

Cuando Web-IO acepta la conexión, se ejecuta el procedimiento Callback. Además se genera una referencia a una rutina Callback para la recepción de datos.

Mediante el envío de la estructura Options al Web-IO, se le está ordenando que, al aplicar una salida transmita la modificación del estado de conmutación a través de la estructura 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);
  }
}
						

Además, al activar el proceso connectupdatedisplay() se habilitan en la aplicación todos los elementos de mando requeridos y se desactiva el botón Connect.


 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;
}
						

En la actual versión de C# ya no está permitido acceder desde un thread (aquí la función Callback) a elementos gráficos de otro thread (forma).

Una solución ofrece aquí el uso de delegados y del método Invoke.

Separar la conexión

La conexión se mantiene hasta que el usuario la finalice pulsando el botón Disconnect o hasta que sea finalizada por el Web-IO.


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!";
  }
}
            

En este caso se llama un procedimiento correspondiente.


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

Para un acceso seguro al thread se ha deslocalizado el restablecimiento de los elementos del formulario en el proceso 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;
}
            

Error de conexión

Todas las acciones correspondientes a la comunicación TCP/IP se ejecutan dentro de la orden Try. Si aparecen errores se activa el disconnect(); método del cliente objeto.

Manejo y comunicación por parte del cliente

Envío de estructuras binarias

Una vez establecida la conexión con el Web-IO, el usuario puede enviar estructura binarias al Web-IO utilizando los correspondientes elementos de programa.


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# no prevé ningún método para el envío directo de estructuras binarias. Los datos binarios solo pueden ser enviados como un array de bytes. Por eso al abrir la función sendstructure se transmite un pointer (puntero). Ese puntero hace referencia al puesto de la memoria a partir del cual se encuentra el contenido de la estructura a enviar. Aquí se pone de manifiesto, por qué las variables de la estructura tienen que estar agrupadas por bytes en la memoria. Como segundo parámetro se transmite la longitud de la estructura.

A través de Marshal.Copy(BufPtr, senddata, 0, Bufsize) se copian los datos de la estructura en un array de bytes. Ese array de bytes será enviado luego al Web-IO.

Poner Outputs

El usuario puede poner los Outputs a través de dos casillas de verificación cb_outputx. El programa utiliza para ello la acción MouseUP de ese objeto. Cuando se registra un MouseUp, es decir se suelta la casilla de verificación de la salida, el programa ejecuta el procedimiento correspondiente y, en función de si está aplicada o no la casilla de verificación, transmite la correspondiente estructura SetBit rellenada 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);
}
            

Solicitar estado de Output/Input

El usuario puede solicitar el estado de los Outputs e Inputs chasqueando el botón correspondiente.


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);
}
            

Mediante el envío de la estructura RegisterRequest se solicitan los estados de conmutación de las entradas y salidas. Web-IO responde a esa solicitud con la estructura RegisterState.

Si solo deben consultarse las entradas, esto se activa pulsando el botón bt_inputs. Para ello se envía la estructura ReadRegister, a la que Web-IO responde con la estructura 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);
}
            

Contadores preguntar/borrar

También los estados de los contadores de la entrada pueden ser consultados o borrados. Para ello se envía la estructura ReadCounter o ReadClearCounter, donde se transmite con CounterIndex el número del contador. Web-IO responde con la estructura 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);
}
						

A través de la estructura ReadAllCounter o ReadClearAllCounter se puede leer o borrar también todos los contadores. Web-IO responde con la estructura 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);
}
						

Recepción de datos del Web-IO

Evaluar e indicar los datos recibidos

Web-IO envía la estructura acorde a la solicitud o la acción que lo activa. Para la recepción de datos se activa el correspondiente procedimiento Callback. Para la evaluación, los primeros 8 bytes del array de bytes recibido rellenan en primer lugar una estructura EADriver a través de una operación de puntero. La aplicación identifica el tipo de estructura a través de la variable EADriver.StructType.

  • EADriver.StructType = 8
    Estructura WriteRegister para el estado de las entradas

  • EADriver.StructType = 31 (hex.)
    Estructura RegisterState para el estado de las entradas y salidas

  • EADriver.StructType = B4 (hex.)
    Estructura Counter para el valor de los diferentes contadores

  • EADriver.StructType = B5 (hex.)
    Estructura AllCounter para el valor de todos los contadores

Para la evaluación, el array de bytes recibido rellena ahora la estructura adecuada a través de una operación de puntero.

Los valores transmitidos de ese modo son evaluados y presentados. Para las entradas y salidas se transmite a través de WriteRegister.Value, RegisterStae.InputValue y RegisterStae.outputValue el patrón de bits de todas las entradas o salidas.


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();
  }
}
						

Para una actualización segura del thread de la indicación se transmite la reproducción del proceso de las EA a través de la estructura IOState al procedimiento IOupdatedisplay. A través de la formación de invoke y delegate se adaptan los elementos de presentación afectados al estado de las EA.


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

Solicitud cíclica de determinados valores

A fin de posibilitar una actualización automática de la indicación, se utiliza un Timer.

Dependiendo de las casillas de verificación para el Polling de Output, Input y Counter se llaman las informaciones correspondientes a un intervalo ajustado del Web-IO.


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();
}
            

El intervalo deseado puede entrarse en el campo correspondiente de texto. En caso de un cambio el intervalo del Timer se adapta automáticamente.


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!";
  }
}
						

El programa ejemplo es compatible con todas las funciones habituales de Web-IO en el modo de socket binario, optimizado para Web-IO 2x entradas digitales, 2x salidas digitales. Para otros modelos de Web-IO puede ser necesario adaptar el programa. Encontrará una descripción detallada de las estructuras binarias en el breve resumen de estructuras binarias o en manual de programación para Web-IO.

Descargar el programa ejemplo


Productos