Wiesemann & Theis GmbH

Tecnología de redes, sensores e interfaces para la industria, la oficina y la informática

Tutorial al Web-IO digital:

Activar Web-IO Digital con Delphi
sockets binarios


Como lenguaje de alto nivel fácil de aprender, Delphi ofrece todo lo necesario para programar aplicaciones TCP/IP. Por eso, también Delphi es un instrumento muy utilizado para crear aplicaciones que se comunican con Web-IO Digital vía sockets binarios. No se necesitan controladores adicionales ni DLL.

Control de Web-IO con C Sharp

Con el siguiente ejemplo de programa Delphi, 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


Elementos de manejo Delphi

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.

Para desarrollar la comunicación TCP se emplea el componente TIdTCPClient de Indy, que es parte integrante de los componentes Delphi.

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 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.

							
Type
  READriver=packed record
    Start_1:word;
    Start_2:word;
    StructType:word;
    StructLength:word;
  end;

  RWriteRegister=packed record
    EADriver : READriver;
    Amount:word;
    Value:word;
  end;

  RSetBits=packed record
    EADriver : READriver;
    Mask:word;
    Value:word;
  end ;

  RRegisterState=packed record
    EADriver : READriver;
    DriverID : word;
    InputValue : word;
    OutputValue : word;
  end;

  RReadCounter=packed record
    EADriver : READriver;
    CounterIndex : word;
  end;

  RCounter=packed record
    EADriver : READriver;
    CounterIndex: word;
    CounterValue: longword;
  end;

  RAllCounter=packed record
    EADriver : READriver;
    CounterNoOf: word;
    CounterValue: array [0..11]of longword;
  end;

  ROptions=packed record
    EADriver : READriver;
    Version : longword;
    Options : longword;
  end;
							
						

En las estructuras es importante que las distintas variables se encuentren agrupadas sucesivamente en la memoria. Delphi 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 =packed record que no haya ningún espacio de memoria sin utilizar entre las variables.

Arranque de programa

Instalar los elementos de manejo

Para el tratamiento de las acciones asíncronas, como la recepción de datos, se define, crea y arranca con el inicio del programa el correspondiente thread de preparación.

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.

							

  .....
  .....
  private
    { Private-Deklarationen }
  public
    procedure ClientSocketThreadRun(Sender: TIdThreadComponent);
    { Public-Deklarationen }
  end;
var
  webio_binary_client: Twebio_binary_client;
  ClientSocketThread : TIdThreadComponent;

implementation

{$R *.DFM}

procedure Twebio_binary_client.FormCreate(Sender: TObject);
begin
  ClientSocketThread := TIdThreadComponent.Create();
  ClientSocketThread.onRun := ClientSocketThreadRun;
  StatusBar1.SimpleText := ’No Connection’;
  bt_disconnect.Enabled := False;
  gb_io.Enabled := False;
end;
							
						

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.

							
procedure Twebio_binary_client.bt_connectClick(Sender: TObject);
begin
  if ed_ip.Text <> ’’ then
  begin
    ClientSocket.Host := ed_ip.Text;
    ClientSocket.Port := strtoint(ed_port.Text);
    ClientSocket.Connect;
  end;
end;
							
						

Se establece la conexión

Tan pronto como el Web-IO acepta la conexión, el elemento de mando ClientSocket ejecuta el procedimiento correspondiente. En la línea de estado aparece la realización de la conexión, los elementos de manejo se liberan para el uso y puede manejarse el botón Disconnect.

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.

							
procedure Twebio_binary_client.bt_disconnectClick(Sender: TObject);
begin
  ClientSocket.Disconnect;
end;

procedure Twebio_binary_client.ClientSocketConnected(Sender: TObject);
var
  Options : structOptions;
  SendBuffer : TIdBytes;
begin
  ClientSocketThread.Active := true;
  StatusBar1.SimpleText := ’Connected to ’ + ed_ip.Text;
  bt_connect.Enabled := False;
  bt_disconnect.Enabled := True;
  gb_io.Enabled := True;
  Options.EADriver.Start_1 := 0;
  Options.EADriver.Start_2 := 0;
  Options.EADriver.StructType := $1F0;
  Options.EADriver.StructLength := $10;
  Options.Version := 1;
  Options.Options := 1;
  SendBuffer := RawToBytes(Options, Options.EADriver.StructLength);
  ClientSocket.IOHandler.Write(SendBuffer);
end;
							
						

Emisor de estructuras binarias

El elemento de control Indy TidTCPClient no puede enviar estructuras directamente. Por eso, antes de cada envío es necesario convertir cada estructura con RawToBytes en un array de bytes.

Separar la conexión

La conexión permanece tanto tiempo hasta que el usuario la finalice chasqueando el botón Disconnect o el Web-IO finalice la conexión.

							
procedure Twebio_ascii_client.bt_disconnectClick(Sender: TObject);
begin
  ClientSocket.Disconnect;
end;
              
						

En este caso el elemento de mando ClientSocket también llama un procedimiento correspondiente.

							
procedure Twebio_ascii_client.ClientSocketDisconnected(Sender: TObject);
begin
  ClientSocketThread.Active := false;
  ClientSocket.Disconnect;
  StatusBar1.SimpleText := ’No Connection’;
  bt_connect.Enabled := True;
  bt_disconnect.Enabled := False;
  gb_io.Enabled := False;
end;
              
						

Manejo y comunicación por parte del cliente

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.

Poner Outputs

El usuario puede poner los Outputs a través de dos casillas de verificación cb_outputx. Para ello el programa utiliza la acción MouseUP de ese objeto. Cuando se registra una acción 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 la casilla de verificación está marcada o no, transmite al Web-IO la estructura SetBit rellenada con los valores respectivos.

							
procedure Twebio_binary_client.cb_outputMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  SetBits : structSetBits;
  SendBuffer : TIdBytes;
begin
  SetBits.EADriver.Start_1 := 0;
  SetBits.EADriver.Start_2 := 0;
  SetBits.EADriver.StructType := $09;
  SetBits.EADriver.StructLength := $0C;
  if sender = cb_output0 then
  begin
    SetBits.Mask := 1;
    if cb_output0.Checked then
      SetBits.Value := 1
    else
      SetBits.Value := 0;
  end;
  if sender = cb_output1 then
  begin
    SetBits.Mask := 2;
    if cb_output1.Checked then
      SetBits.Value := 2
    else
      SetBits.Value := 0;
  end;
  SendBuffer := RawToBytes(SetBits, SetBits.EADriver.StructLength);
  ClientSocket.IOHandler.Write(SendBuffer);
end;
							
						

Solicitar estado de Output/Input

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

							
procedure Twebio_binary_client.bt_outputs_readClick(Sender: TObject);
var
  EADriver : structEADriver;
  SendBuffer : TIdBytes;
begin
  EADriver.Start_1 := 0;
  EADriver.Start_2 := 0;
  EADriver.StructType := $21;
  EADriver.StructLength := $08;
  SendBuffer := RawToBytes(EADriver, EADriver.StructLength);
  ClientSocket.IOHandler.Write(SendBuffer);
end;
							
						

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.

							
procedure Twebio_binary_client.bt_inputs_readClick(Sender: TObject);
var
  EADriver : structEADriver;
  SendBuffer : TIdBytes;
begin
  EADriver.Start_1 := 0;
  EADriver.Start_2 := 0;
  EADriver.StructType := $01;
  EADriver.StructLength := $08;
  SendBuffer := RawToBytes(EADriver, EADriver.StructLength);
  ClientSocket.IOHandler.Write(SendBuffer);
end;
							
						

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.

							
procedure Twebio_binary_client.bt_counter_readClick(Sender: TObject);
var
  ReadCounter : structReadCounter;
  SendBuffer : TIdBytes;
begin
  ReadCounter.EADriver.Start_1 := 0;
  ReadCounter.EADriver.Start_2 := 0;
  ReadCounter.EADriver.StructType := $B0;
  ReadCounter.EADriver.StructLength := $0A;
  if sender = bt_counter_read0 then ReadCounter.CounterIndex := 0;
  if sender = bt_counter_read1 then ReadCounter.CounterIndex := 1;
  SendBuffer := RawToBytes(ReadCounter, ReadCounter.EADriver.StructLength);
  ClientSocket.IOHandler.Write(SendBuffer);
end;

procedure Twebio_binary_client.bt_counter_clearClick(Sender: TObject);
var
  ReadCounter : structReadCounter;
  SendBuffer : TIdBytes;
begin
  ReadCounter.EADriver.Start_1 := 0;
  ReadCounter.EADriver.Start_2 := 0;
  ReadCounter.EADriver.StructType := $C0;
  ReadCounter.EADriver.StructLength := $0A;
  if sender = bt_counter_clear0 then ReadCounter.CounterIndex := 0;
  if sender = bt_counter_clear1 then ReadCounter.CounterIndex := 1;
  SendBuffer := RawToBytes(ReadCounter, ReadCounter.EADriver.StructLength);
  ClientSocket.IOHandler.Write(SendBuffer);
end;
							
						

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.

							
procedure Twebio_binary_client.bt_counter_readallClick(Sender: TObject);
var
  EADriver : structEADriver;
  SendBuffer : TIdBytes;
begin
  EADriver.Start_1 := 0;
  EADriver.Start_2 := 0;
  EADriver.StructType := $B1;
  EADriver.StructLength := $08;
  SendBuffer := RawToBytes(EADriver, EADriver.StructLength);
  ClientSocket.IOHandler.Write(SendBuffer);
end;

procedure Twebio_binary_client.bt_counter_clearallClick(Sender: TObject);
var
  EADriver : structEADriver;
  SendBuffer : TIdBytes;
begin
  EADriver.Start_1 := 0;
  EADriver.Start_2 := 0;
  EADriver.StructType := $C1;
  EADriver.StructLength := $08;
  SendBuffer := RawToBytes(EADriver, EADriver.StructLength);
  ClientSocket.IOHandler.Write(SendBuffer);
end;
							
						

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 vía BytesToRaw 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 vía BytesToRaw la estructura que corresponda.

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.

							
procedure Twebio_binary_client.ClientSocketThreadRun(Sender: TIdThreadComponent);
var
  ReceiveBuffer : TIdBytes;
  EADriver : structEADriver;
  WriteRegister : structWriteRegister;
  RegisterState : structRegisterState;
  Counter : structCounter;
  AllCounter : structAllCounter;
begin
  while not ClientSocket.IOHandler.InputBufferIsEmpty do
  begin
    SetLength(ReceiveBuffer, length(ReceiveBuffer)+1);
    ReceiveBuffer[length(ReceiveBuffer)-1] := ClientSocket.IOHandler.ReadByte;
  end;
  if length(ReceiveBuffer) > 7 then
    BytesToRaw(ReceiveBuffer, EADriver, 8);
    case EADriver.StructType of

    $08 : begin
            if length(ReceiveBuffer) >= EADriver.StructLength then
            begin
              BytesToRaw(ReceiveBuffer, WriteRegister, EADriver.StructLength);
              if WriteRegister.Value and 1 = 1 then
                cb_input0.Checked := True
              else
                cb_input0.Checked := False;
              if WriteRegister.Value and 2 = 2 then
                cb_input1.Checked := True
              else
                cb_input1.Checked := False;
            end;
          end;
    $31 : begin
            if length(ReceiveBuffer) >= EADriver.StructLength then
            begin
              BytesToRaw(ReceiveBuffer, RegisterState, EADriver.StructLength);
              if RegisterState.InputValue and 1 = 1 then
                cb_input0.Checked := True
              else
                cb_input0.Checked := False;
              if RegisterState.InputValue and 2 = 2 then
                cb_input1.Checked := True
              else
                cb_input1.Checked := False;
              if RegisterState.OutputValue and 1 = 1 then
                cb_output0.Checked := True
              else
                cb_output0.Checked := False;
              if RegisterState.OutputValue and 2 = 2 then
                cb_output1.Checked := True
              else
                cb_output1.Checked := False;
            end;
          end;
    $B4 : begin
            if length(ReceiveBuffer) >= EADriver.StructLength then
            begin
              BytesToRaw(ReceiveBuffer, Counter, EADriver.StructLength);
              if Counter.CounterIndex = 0 then
                ed_counter0.Text := IntToStr(Counter.CounterValue);
              if Counter.CounterIndex = 1 then
                ed_counter1.Text := IntToStr(Counter.CounterValue);
            end;
          end;
    $B5 : begin
            if length(ReceiveBuffer) >= EADriver.StructLength then
            begin
              BytesToRaw(ReceiveBuffer, AllCounter, EADriver.StructLength);
              ed_counter0.Text := IntToStr(AllCounter.CounterValue[0]);
              ed_counter1.Text := IntToStr(AllCounter.CounterValue[1]);
            end;
          end;
    end;
end;
							
						

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.

							
procedure Twebio_binary_client.timer_pollingTimer(Sender: TObject);
begin
  if ClientSocket.Connected and cb_output_polling.Checked then
    bt_outputs_readClick(self);
  if ClientSocket.Connected and cb_input_polling.Checked then
    bt_inputs_readClick(self);
  if ClientSocket.Connected and cb_counter_polling.Checked then
    bt_counter_readallClick(self);
end;
							
						

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

							
procedure Twebio_binary_client.ed_intervalChange(Sender: TObject);
begin
  timer_polling.Interval := strtoint(ed_interval.Text);
end;
							
						

El ejemplo de programación 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 ejemplo de programación


Productos



^