Enviar datos UDP independientemente de Libreria C#

  • 1 Respuestas
  • 5949 Vistas

ErnestoH

  • Principiante
  • Mensajes: 2
Enviar datos UDP independientemente de Libreria C#
« : noviembre 19, 2012, 12:43:25 pm »
Estimado Boris

Estoy programando un PLC para controlar una bomba de calor geotermica.

Me encuentro con el problema que el PLC STX8081-C1 no reconoce secuencias crudas enviadas por ejemplo con el UDP Test Tool 3.0 o con la utilización del socket IP de .Net. (en cambio todo funciona OK utilizando la librerias de Slicetex). Seguramente me falta una secuencia. ¿me la podrias enviar?

Te adjunto el codigo c# que no funciona.

Muchas gracias.

Saludos.

Ernesto

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 2324
  • Soporte Técnico
Re: Enviar datos UDP independientemente de Libreria C#
« Respuesta #1 : noviembre 19, 2012, 13:21:57 pm »
Estimado Ernesto,

La libreria en C# de Slicetex contiene una serie de secuencias para enviar un dato con
UDP al PLC que forman parte del protocolo CSP (Command Server Protocol) del PLC.

Si necesitas enviar datos vía UDP independientemente de la libreria C#, debes seguir
una secuencia mínima para cumplir los requisitos del PLC (protocolo CSP).

A continuación te paso un ejemplo.

Lo primero que debes hacer es crear un array o buffer para almacenar el encabezado
del protocolo y luego el dato propiamente a enviarle al PLC.

Entonces a continuación te listo unas constantes que describen la trama
del paquete a enviar.

El paquete tiene la siguiente estructura:

Código: [Seleccionar]
// ---------------------------------------------------------------------------
// COMMAND INPUT PACKET OFFSETS
//
// Packet:
// [CMD_PASS0][CMD_PASS1][CMD_PASS2][CMD_PASS3][CMD_PROTO][CMD_TYPE]
// [CMD_ARGSIZE0][CMD_ARGSIZE1][CMD_ID][CMD_ARGS]
//
// Fields:
// [CMD_PASS0...3] = 32-bits password for access to command server.
// [CMD_PROTO] = Protocol information (protocol version on 3 LSBIT).
// [CMD_TYPE] = Command Type (QUIET, GO, etc. See below).
// [CMD_ARGSIZE0...1] = Command argument size (2-bytes).
// [CMD_ID] = Command Id (command name) for execute. See pbcmd.h.
// [CMD_ARGS] = Command arguments received (variable size field).
// ---------------------------------------------------------------------------

#define CMDIN_PASS_OFFSET       (0)
#define CMDIN_PROTO_OFFSET      (4)
#define CMDIN_TYPE_OFFSET       (5)
#define CMDIN_ARGSIZE0_OFFSET   (6)
#define CMDIN_ARGSIZE1_OFFSET   (7)
#define CMDIN_ID_OFFSET         (8)
#define CMDIN_ARGS_OFFSET       (9)

// UDP PORTS

#define CMDSERV_SERVER_PORT     (4950)

// CSP INFO

#define CMDSERV_PROTO_VERSION   (2)


// COMMAND COMMAND TYPES CODES

#define CMD_TYPE_QUIET        (0xFA)  // Ignore command output. Output size=0.
#define CMD_TYPE_GO           (0x55)  // Get command output.

Entonces, suponiendo que creas un buffer o array llamado "Data" para enviarlo por
UDP, y queres solamente enviar los valores "1" y "55" en dos bytes
diferentes, debes cargar el array de la siguiente manera:

Código: [Seleccionar]

   // Configurar CSP Header

   // Password del PLC.
   Data[CMDIN_PASS_OFFSET] = 0
   Data[CMDIN_PASS_OFFSET+1] = 0
   Data[CMDIN_PASS_OFFSET+2] = 0
   Data[CMDIN_PASS_OFFSET+3] = 0

   Data[CMDIN_PROTO_OFFSET] = CMDSERV_PROTO_VERSION
   Data[CMDIN_TYPE_OFFSET] = CMD_TYPE_QUIET

   Data[CMDIN_ARGSIZE0_OFFSET] = 3  // 1 + 2 bytes enviados
   Data[CMDIN_ARGSIZE1_OFFSET] = 0

   Data[CMDIN_ID_OFFSET] = 6  // Command Name.

   Data[CMDIN_ARGS_OFFSET] = 2  // Bytes to send or Arg. Size = 2 bytes.

   // Set data values.
   Data[CMDIN_ARGS_OFFSET+1] = 1
   Data[CMDIN_ARGS_OFFSET+2] = 55


Entonces, si envias el array "Data" por UDP al puerto "4950" de la placa, el PLC
al recibirlo va a llamar al evento "OnUdpRx" y luego desde alli podes
leer con la funcion UdpRxDataRead() los dos bytes
recibidos (en este caso con el valor "1" y "55" respectivamente).

Podes enviar hasta 252 bytes al PLC.

Recorda activar el evento "OnUdpRx" del PLC, de lo contrario los bytes recibidos
son descartados.

Esta es la forma simple de enviar datos al PLC. Hay otro método que permite conocer
si el PLC recibe los datos, etc. Pero eso es mas avanzado.

En los archivos adjuntos subo dos ejemplos:

- Udp_Tx_CSP.zip: Ejemplo para transmitir de un PLC a otro PLC en Pawn.
- sendcmd.php: Ejemplo para transmitir UDP al PLC desde PHP.

Finalmente, cuando el PLC transmite datos UDP utilizando la funcion UdpSend()
lo hace en UDP crudo, sin protocolo intermedio.

Cualquier duda, avisame.

Ejemplo PAWN:

Código: [Seleccionar]

// ---------------------------------------------------------------------------
// COSNTANTES
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
// COMMAND INPUT PACKET OFFSETS
//
// Packet:
// [CMD_PASS0][CMD_PASS1][CMD_PASS2][CMD_PASS3][CMD_PROTO][CMD_TYPE]
// [CMD_ARGSIZE0][CMD_ARGSIZE1][CMD_ID][CMD_ARGS]
//
// Fields:
// [CMD_PASS0...3] = 32-bits password for access to command server.
// [CMD_PROTO] = Protocol information (protocol version on 3 LSBIT).
// [CMD_TYPE] = Command Type (QUIET, GO, etc. See below).
// [CMD_ARGSIZE0...1] = Command argument size (2-bytes).
// [CMD_ID] = Command Id (command name) for execute. See pbcmd.h.
// [CMD_ARGS] = Command arguments received (variable size field).
// ---------------------------------------------------------------------------

#define CMDIN_PASS_OFFSET       (0)
#define CMDIN_PROTO_OFFSET      (4)
#define CMDIN_TYPE_OFFSET       (5)
#define CMDIN_ARGSIZE0_OFFSET   (6)
#define CMDIN_ARGSIZE1_OFFSET   (7)
#define CMDIN_ID_OFFSET         (8)
#define CMDIN_ARGS_OFFSET       (9)

// UDP PORTS

#define CMDSERV_SERVER_PORT     (4950)

// CSP INFO

#define CMDSERV_PROTO_VERSION   (2)


// COMMAND COMMAND TYPES CODES

#define CMD_TYPE_QUIET        (0xFA)  // Ignore command output. Output size=0.
#define CMD_TYPE_GO           (0x55)  // Get command output.


// ---------------------------------------------------------------------------
// Command      : UdpRx
//
// Description  : If command is enabled, received data is send to PAWN script.
//
// ARGUMENTS    :
//
//    - Size     = A0 -> Data Size in bytes (max size 252).
//    - Data     = A1:A252 -> Data to send to PAWN script.
//
// RETURN       :
//
//    - Stat    = R0 -> Operation Status. See UDPRX_STAT values on nudp.h
//                file. Normal return should be UDPRX_STAT_OK.
//
// ---------------------------------------------------------------------------

#define PBCMD_UdpRx                   (6)   // Command ID.
#define PBCMD_UdpRx_ASIZE             (253) // Argument size in bytes.
#define PBCMD_UdpRx_RSIZE             (1)   // Return size in bytes.

// ---------------------------------------------------------------------------
// FUNCIONES
// ---------------------------------------------------------------------------

// ***************************************************************************
// PlcMain(): Funcion principal. Punto de entrada al script.
//
// ENTRADAS:
//
//    - Ninguna.
//
// SALIDAS:
//
//    - Ninguna.
//
// ***************************************************************************

PlcMain()
{
   // Crear un array para almacenar los bytes a enviar.
   new Data[10+2]

   // Limpiar LCD.
   LcdClear()

   // Mensaje de bienvenida...
   LcdPrintf(0, 0, "CSP Test")
   LcdPrintf(0, 1, "Enviando...")

   // Configurar CSP Header
   Data[CMDIN_PASS_OFFSET] = 0
   Data[CMDIN_PASS_OFFSET+1] = 0
   Data[CMDIN_PASS_OFFSET+2] = 0
   Data[CMDIN_PASS_OFFSET+3] = 0
   Data[CMDIN_PROTO_OFFSET] = CMDSERV_PROTO_VERSION
   Data[CMDIN_TYPE_OFFSET] = CMD_TYPE_QUIET

   Data[CMDIN_ARGSIZE0_OFFSET] = 3
   Data[CMDIN_ARGSIZE1_OFFSET] = 0

   Data[CMDIN_ID_OFFSET] = PBCMD_UdpRx

   Data[CMDIN_ARGS_OFFSET] = 2  // Cmd UdpRx Arg. Size (2 bytes)

   // Set data values.
   Data[CMDIN_ARGS_OFFSET+1] = 1
   Data[CMDIN_ARGS_OFFSET+2] = 55

   // Ciclo principal del programa.
   while(1)
   {
      // Enviar paquete UDP a direccion 192.168.1.81, puerto 4980.
      UdpSend(192,168,1,81, CMDSERV_SERVER_PORT, 12, Data, false)

      // Limitar valor del sexto byte a 255.
      if(Data[CMDIN_ARGS_OFFSET+1] == 1)
      {
         Data[CMDIN_ARGS_OFFSET+1] = 0
      }
      else
      {
         Data[CMDIN_ARGS_OFFSET+1] = 1
      }

      // Pausar programa por 1 segundo y conmutar led.
      DelayS(1)
      LedToggle()
   }
}


Ejemplo con PHP:

Código: [Seleccionar]

<?php

//phpinfo();

// Enviar Datos al PLC
send_CSP(1500);

/**
  * Sends SIMPLE CSP COMMAND.

  *
  * @param int    $delay delay in msec
  * @param string    $host target host
  * @param int    $port target port (udp)
  */
function send_CSP($delay$host="plc.dyndns.org"$port=4950)
{
   
$datatosend "";
   
$packet = array();

   for(
$n=0;$n<20;$n++)
   {
      
$packet[$n] = 0x00;
   }

   
// PASS
   
$packet[0] = 0;
   
$packet[1] = 0;
   
$packet[2] = 0;
   
$packet[3] = 0;
   
   
// PROTO
   
$packet[4] = 2;
   
   
// TYPE
   
$packet[5] = 0xFA// QUIET
   
   // ARGSIZE0
   
$packet[6] = 3;
   
// ARGSIZE1
   
$packet[7] = 0;
   
   
// CMD ID 
   
$packet[8] = 6;  // PBCMD_UdpRx
   
   // ARGS SIZE
   
$packet[9] = 2;  // 2 bytes
   
   // ARG DATA VALUES
   
$packet[10] = 1;
   
$packet[11] = 55;

   
// Convert packet to string.
   
foreach($packet as $value)
   {
      
$datatosend.=chr($value);
   }
   
   
print_r($packet);   

     
     
$socket socket_create(AF_INETSOCK_DGRAMSOL_UDP);
     
     
socket_sendto($socket$datatosendstrlen($datatosend), 0$host$port);
     
socket_close($socket);
     
usleep($delay*1000);
 }
?>


« Última Modificación: diciembre 01, 2012, 12:19:26 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com