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:
// ---------------------------------------------------------------------------
// 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:
// 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:
// ---------------------------------------------------------------------------
// 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:
<?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_INET, SOCK_DGRAM, SOL_UDP);
socket_sendto($socket, $datatosend, strlen($datatosend), 0, $host, $port);
socket_close($socket);
usleep($delay*1000);
}
?>