Servidor TCP

  • 14 Respuestas
  • 1692 Vistas

coloriginal

  • Aprendiz
  • **
  • Mensajes: 30
Servidor TCP
« : noviembre 11, 2015, 09:40:50 am »
Buenos días Boris, como quedamos personalmente te hago por esta vía el pedido para implementar un Servidor TCP en el PLC, el nro máximo de bytes transmitidos por operación no supera de 70. Desde ya muchas Gracias

A.S. Cristian M. Colovatto
M.P.:3076
Cel.0351-157428908
A.S.: Cristian M. Colovatto
M. P. :3076
(0351)-152635979

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1625
  • Soporte Técnico
Re:Servidor TCP
« Respuesta #1 : noviembre 11, 2015, 10:33:36 am »
Buenos días Cristian,

Muy bien, lo implementamos. Cuando tenga novedades te estoy avisando.

Saludos
« Última Modificación: noviembre 11, 2015, 10:39:16 am por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1625
  • Soporte Técnico
Re:Servidor TCP
« Respuesta #2 : noviembre 20, 2015, 05:22:50 am »
Buenos días Cristian,

Ya está prácticamente listo el servidor TCP, con las pruebas efectuadas que hice.

Solo falta subir las actualizaciones de software y describir las funciones disponibles.

De no mediar inconvenientes, este lunes podría tener una version disponible.

Estamos en contacto.

Enviado desde un dispositivo móvil usando Taptalk.

SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

coloriginal

  • Aprendiz
  • **
  • Mensajes: 30
Re:Servidor TCP
« Respuesta #3 : noviembre 20, 2015, 09:27:49 am »
Estupendo me alegro que ya tengas casi terminado el desarrollo. Espero con ansias apenas lo tengas listo así puedo comenzar la implementación.

A.S.: Cristian M. Colovatto
M. P. :3076
(0351)-157428908
« Última Modificación: noviembre 20, 2015, 11:00:17 am por coloriginal »
A.S.: Cristian M. Colovatto
M. P. :3076
(0351)-152635979

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1625
  • Soporte Técnico
Re:Servidor TCP
« Respuesta #4 : noviembre 22, 2015, 16:08:18 pm »
Buenas tardes Cristian,

Ya esta disponible la actualización para utilizar el servidor TCP en el PLC.

Necesitas:


Luego de actualizado el software y firmware, podes utilizar los ejemplos.

En el próximo mensaje voy a describir detalladamente cada función disponible en el Servidor TCP, pero para empezar rápido, en este mensaje te explico un ejemplo básico de uso, así como te adjunto un proyecto para usarlo.

EJEMPLO TCP-SERVER-1:

El archivo TcpServer1.zip contiene un proyecto StxLadder para cargar en el PLC (antes debes cambiar el modelo de PLC al que tenes adquirido) y luego compilar+cargar (tecla F8).

El ejemplo utiliza VirtualHMI para mostrar en pantalla de la PC/ANDROID los datos recibidos por el servidor TCP del PLC.

Para probar el servidor, podes enviar datos utilizando el cliente TcpClient1.zip que te adjunto, que fue desarrollado en Microsoft Visual C# para hacer las pruebas básicas.

Entonces, cargar el proyecto TcpServer1.zip en el PLC, luego abris VirtualHMI (lo activas) y tocas la tecla "ON", en la pantalla de HMI vas a tener un mensaje de Bienvenida.

Luego desde el cliente TcpClient1.zip, te conectas al PLC y envias 6 bytes con cualquier valor, el PLC lo recibe y muestra en la pantalla de VirtualHMI. Finalmente, transmite la cadena "Hello" de vuelta al cliente TCP, y la observas en el programa TcpClient1.zip.

Con eso probas la conexion TCP.

En codigo, se hace lo siguiente (muestro las partes significativas al servidor TCP):

Inicialización

Código: (Pawn) [Seleccionar]

   // Inicializar TCP Server.
   // Puerto: 48000
   // Timeout Idle: 30 segundos.
   TcpServerInit(48000, 30)
   
   // Activar evento para recepcion de datos de cliente.
   TcpServerSetRxEvent()   


La función TcpServerInit() inicializa y activa el servidor TCP. El puerto donde escucha es el 48000, y tiene un timeout-idle de 30 segundos (esto quiere decir que si el cliente conectado no interactua por mas de 30 segundos, es desconectado para liberar la conexión).

La función TcpServerSetRxEvent() activa el evento @OnTcpServerRx() que es llamado cuando datos nuevos son recibidos por el servidor provenientes de un cliente TCP.

Evento de recepción:

Código: [Seleccionar]

// ********************************************************************************
// Evento        : OnTcpServerRx()
// Descripcion : Es llamado cuando datos de un cliente remoto son recibidos.
// ********************************************************************************

@OnTcpServerRx()
{
new Id

//
// Obtener conexiones con datos sin leer.
//

while((Id=TcpServerGetUnreadId()) > 0)
{
// Leer datos.
TcpServerRead(Id, RxData, 10)

// Mostrar datos recibidos en Virtual HMI.
        nLcdPrintf(0, 0, LCD_CLRALL, "DATOS RECIBIDOS")
        nLcdPrintf(0, 1, LCD_NONE, "CONN ID = %d", Id)
        nLcdPrintf(0, 2, LCD_NONE, "[0]: %d [1]: %d [2]: %d", RxData[0], RxData[1], RxData[2])
        nLcdPrintf(0, 3, LCD_NONE, "[3]: %d [4]: %d [5]: %d", RxData[3], RxData[4], RxData[5])
   
        // Responder con un mensaje usando el Id de la conexion que recibio los datos.
        TcpServerSend(Id, TxData, 5)
}
}

El evento @OnTcpServerRx() se llama cuando alguna conexión de un cliente conectado al servidor TCP recibe datos.

Cada conexión aceptada por el servidor se identifica con un ID (numero positivo mayor a 0), que sirve para manejar la conexión.

Entonces, cada vez que leemos, enviamos datos o queremos cerrar una conexión, debemos utilizar el ID provisto por el servidor.

El loop "while((Id=TcpServerGetUnreadId()) > 0)" obtiene en cada iteracion el ID de la conexión que tiene datos recibidos sin leer. Cuando los datos son leidos y no hay datos nuevos en ninguna conexion, el retorno de TcpServerGetUnreadId() es 0, y se sale del loop.

La linea "TcpServerRead(Id, RxData, 10)" lee como máximo 10 bytes de la conexión Id. Los datos son almacenados en el array RxData.

Luego se imprimen 6 bytes en la pantalla de VirtualHMI con la funcion nLcdPrintf().

La linea TcpServerSend(Id, TxData, 5) responde enviando 5 bytes del array TxData a la conexión Id.

Adicionalmente, el ejemplo con la tecla "M1" envia datos a los clientes activos y con la tecla "M2" de VirtualHMI aborta todas las conexiones activas.

En otro Post, voy a subir mas ejemplos y descripciones de todas las funciones.




« Última Modificación: noviembre 22, 2015, 16:10:32 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1625
  • Soporte Técnico
Re:Servidor TCP
« Respuesta #5 : noviembre 22, 2015, 16:24:16 pm »
Adjunto otro ejemplo: TcpServer2.zip

Similar al ejemplo anterior, pero hace uso de todos los eventos del servidor.

  • @OnTcpServerConnected(): Al recibir una nueva conexión.
  • @OnTcpServerClosed(): Al cerrarse una conexión por parte del cliente.
  • @OnTcpServerRx(): Al recibir nuevos datos.
  • @OnTcpServerTx(): Al finalizar de transmitir datos pendientes.

Luego subo descripciones de cada función del servidor.
« Última Modificación: noviembre 22, 2015, 16:39:46 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

coloriginal

  • Aprendiz
  • **
  • Mensajes: 30
Re:Servidor TCP
« Respuesta #6 : noviembre 23, 2015, 01:46:38 am »
Muchísimas gracias Boris, estaré realizando pruebas y te comentaré como resulta todo.
A.S.: Cristian M. Colovatto
M. P. :3076
(0351)-152635979

coloriginal

  • Aprendiz
  • **
  • Mensajes: 30
Re:Servidor TCP
« Respuesta #7 : noviembre 23, 2015, 11:16:13 am »
      Buenas tardes Boris veo que en la línea que puse abajo mencionas que lee como máximo 10 bytes de la conexión, pero asumo que esto se da debido a que en el ultimo parámetro de la función pones 10, esto se puede modificar o conviene dejarlo asi?

"La linea "TcpServerRead(Id, RxData, 10)" lee como máximo 10 bytes de la conexión Id. Los datos son almacenados en el array RxData."

A.S.: Cristian M. Colovatto
M. P. :3076
(0351)-152635979

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1625
  • Soporte Técnico
Re:Servidor TCP
« Respuesta #8 : noviembre 23, 2015, 18:22:33 pm »
SERVIDOR TCP/IP - FUNCIONES PAWN DISPONIBLES

Actualmente el servidor soporta hasta (2) dos conexiones simultáneamente.
Si se excede ese valor, las conexiones nuevas serán rechazadas hasta que esté libre alguna.

La constante TCPSERV_MAX_CONNECTIONS contiene el número máximo de conexiones simultáneas,
así como la función TcpServerGetMaxId() que retorna el mismo valor.

Cada conexión aceptada por el servidor, se transforma en una conexión activa que se identifica con un "Id",
que es un numero positivo y mayor a cero. El valor del "Id" debe usarse para leer o enviar datos por una
conexión determinada, o para cualquier operación donde deba aplicarse a una conexión en particular.

Luego crearemos la nota de aplicación propiamente dicha con la documentación para el servidor, pero mientras tanto,
esta son las funciones disponibles.


TcpServerInit(ServerPort=48000, TimeoutIdle=10)

Inicializa y activa el servidor TCP/IP.

ENTRADAS:

   - ServerPort = Puerto TCP donde escucha conexiones el servidor.
   - TimeoutIdle = Segundos de timeout-idle antes de desconectar a un cliente por inactividad. Máximo 125 segundos.

RETORNO:

   - (  0  ) = Operación exitosa.
   - ( -1  ) = Error, El servidor ya se encuentra inicializado.
   - ( -2  ) = Error, falla de inicialización, error de memoria.
   - ( -10 ) = Error, puerto TCP invalido.

EJEMPLO:

Código: (Pawn) [Seleccionar]
   // Inicializar TCP Server.
   // Puerto: 48000
   // Timeout Idle: 30 segundos.
   TcpServerInit(48000, 30)

Nota: Se recomienda utilizar un valor de TimeoutIdle lo más pequeño posible, de tal forma que si no hay actividad por parte del cliente antes de ese periodo, la conexión se libere para otro potencial cliente.

Bajo este criterio, cada cliente debe enviar antes del tiempo TimeoutIdle algún dato para que la conexión permanezca abierta. Así mismo, el cliente puede cerrar la conexión en cualquier momento para liberarla (muy recomendado, si la misma no va a usarse por un periodo largo).


TcpServerGetNewId()

Retorna el Id de conexiones nuevas. En cada llamada retorna un Id diferente si hay conexiones nuevas,
de lo contrario retorna 0.

RETORNO:

   - (  >0  ) = Id de conexión nueva
   - (   0  ) = No existen nuevas conexiones.

EJEMPLO:

Código: (Pawn) [Seleccionar]
        new ConnId[TCPSERV_MAX_CONNECTIONS+1]
new Id

        // Obtener todos los Id de conexión nuevas aceptadas.
while((Id=TcpServerGetNewId()) > 0)
{
// Actualizar y guardar Id en memoria con conexiones activas.
ConnId[Id] = Id;
}
   
En cada elemento del array ConnId se mantiene el Id de una conexión activa, caso contrario,
el valor del elemento es 0.


TcpServerSend(Id, Data[], Length=1)

Envía datos a través de una conexión TCP activa del servidor.

ENTRADAS:

   - Id = Identificador de conexión.
   - Data[] = Array con datos a enviar. Cada elemento representa un byte.
   - Length = Numero de bytes a enviar (máximo 70 bytes).

RETORNO:

   - (    0   ) = Operación exitosa.
   - (   -1   ) = Error en Id de conexión (conexión cerrada, no existe, etc).
   - (   -2   ) = Error, existen datos pendientes para transmitir. Esperar.
   - (   -3   ) = Error, Length excede el valor máximo a transmitir permitido.
   - (   -20  ) = Error en dirección de Data[].

EJEMPLO:

Código: (Pawn) [Seleccionar]
   new TxData[5] = {'H', 'e', 'l', 'l', 'o' }

   // Enviar 5 bytes del array TxData[] usando la conexión Id=1.
   TcpServerSend(1, TxData, 5)


TcpServerRead(Id, Data[], Max=1)

Lee los datos recibidos de una conexión TCP activa del servidor.

ENTRADAS:

   - Id = Identificador de conexión.
   - Data[] = Retorno en array con los datos leídos. Cada elemento representa un byte.
   - Max = Máximo numero de bytes a copiar en Data[]. Si el numero de bytes recibidos es menor a Max, los elementos restantes de Data[] son llenados con el valor 0.

RETORNO:

   - (   >0   ) = Operación exitosa, numero de bytes leídos.
   - (   -1   ) = Error en Id de conexión (conexión cerrada, no existe, etc).
   - (   -2   ) = Error, no hay datos pendientes para leer.
   - (   -3   ) = Error, el valor Max excede el tamaño del buffer interno de recepción (máximo 70 bytes).
   - (   -20  ) = Error en dirección de Data[].

EJEMPLO:

Código: (Pawn) [Seleccionar]
   new RxData[10]
   
   // Leer hasta 10 bytes del Id de conexión 1 y almacenar en RxData[].
   if(TcpServerRead(1, RxData, 10) > 0)
   {
      // Si el primer byte recibido tiene el valor 88 conmutar RELAY1.
      if(RxData[0] == 88)
      {
         RelayToggle(RELAY1)
      }
   }
   

TcpServerGetUnreadId()

Obtiene los Id de conexiones con datos no leídos. En cada llamada retorna un Id diferente si la conexión tiene
datos sin leer, de lo contrario retorna 0.

RETORNO:

   - (  >0  ) = Id de conexión con datos no leídos
   - (   0  ) = No existen conexiones con datos sin leer.

EJEMPLO:

Código: (Pawn) [Seleccionar]
        new TxData[5] = {'H', 'e', 'l', 'l', 'o' }
        new RxData[10]
        new Id

//
// Obtener conexiones con datos sin leer.
//

while((Id=TcpServerGetUnreadId()) > 0)
{
// Leer datos en RxData[], hasta 10 bytes.
TcpServerRead(Id, RxData, 10)
   
        // Responder con un mensaje usando el Id de la conexión que recibió los datos.
        TcpServerSend(Id, TxData, 5)
}


TcpServerGetDataSentId()

Obtiene los Id de conexiones que transmitieron datos exitosamente. En cada llamada retorna un Id diferente si la conexión transmitió los datos, de lo contrario retorna 0.

Esta función es útil para determinar conexiones que transmitieron los datos previamente cargados con TcpServerSend(). De esta forma, podemos continuar enviando los datos siguientes al cliente.

RETORNO:

   - (  >0  ) = Id de conexión con datos transmitidos.
   - (   0  ) = No existen conexiones con datos transmitidos.

EJEMPLO:

Código: (Pawn) [Seleccionar]
   new TxData[2]
   new Sample
   new Id

   // Obtener conexiones con datos transmitidos.
   while((Id=TcpServerGetDataSentId()) > 0)
   {
      // Generar nuevos datos leyendo datos del canal analógico 1.
      // Enviar los 10 bits en bytes separados.
      Sample = VinRead(1)
      TxData[0] = Sample
      TxData[1] = Sample >> 8
     
      // Enviar muestra analógica
      TcpServerSend(Id, TxData, 2)
    }


TcpServerCheckUnreadId(Id)

Comprueba si una conexión tiene datos recibidos sin leer.

ENTRADAS:

   - Id = Identificador de conexión.

RETORNO:

   - (    1   ) = Datos recibidos sin leer.
   - (    0   ) = No hay datos recibidos sin leer.

EJEMPLO:
   
Código: (Pawn) [Seleccionar]
   new RxData[10]

   // Comprobar si la conexión 1 tiene datos recibidos sin leer.
   if(TcpServerCheckUnreadId(1))
   {
      // Leer datos en RxData[], hasta 10 bytes.
      TcpServerRead(1, RxData, 10)
   }


TcpServerCheckTxPendingId(Id)

Comprueba si una conexión tiene datos pendientes para transmitir.

ENTRADAS:

   - Id = Identificador de conexión.

RETORNO:

   - (    1   ) = Datos pendientes para transmitir.
   - (    0   ) = No hay datos pendientes para transmitir.

EJEMPLO:
   
Código: (Pawn) [Seleccionar]
   new TxData[5] = {'H', 'e', 'l', 'l', 'o' }

   // Comprobar si la conexión 1 transmitió todos los datos y esta
   // lista para transmitir nuevamente.
   
   if(TcpServerCheckTxPendingId(1) == 0)
   {
      // Enviar datos.
      TcpServerSend(1, TxData, 5)
   }


TcpServerCheckClosedId(Id)

Comprueba si una conexión está cerrada.

ENTRADAS:

   - Id = Identificador de conexión.

RETORNO:

   - (    1   ) = Conexión cerrada.
   - (    0   ) = Conexión activa.

EJEMPLO:

Código: (Pawn) [Seleccionar]
   new TxData[5] = {'H', 'e', 'l', 'l', 'o' }

   // Comprobar si la conexión 1 no está cerrada.
   if(TcpServerCheckClosedId(1) == 0)
   {
      // Transmitir datos en la conexión abierta.
      TcpServerSend(1, TxData, 5)
   }


TcpServerAbortId(Id)

Aborta una conexión.

ENTRADAS:

   - Id = Identificador de conexión.

RETORNO:

   - (    0   ) = Éxito, conexión pendiente para abortar.
   - (    -1  ) = Error, conexión inválida (no existe, cerrada, etc).

EJEMPLO:

Código: (Pawn) [Seleccionar]
   // Abortar conexión de entrada digital DIN1 esta activa.
   if(DinValue(DIN1))
   {
      // Abortar conexión 1.
      TcpServerAbortId(1)
   }


TcpServerProcessId(Id)

Fuerza el procesamiento de una conexión activa inmediatamente. Si hay datos pendientes para enviar, los mismos serán transmitidos inmediatamente si es posible.

Esto evita esperar que el sistema procese la conexión (por defecto puede tardar hasta 0.5 segundos) y acelera la transmisión de datos.

ENTRADAS:

   - Id = Identificador de conexión.

RETORNO:

   - (    1   ) = Conexión procesada.
   - (    0   ) = Error, conexión inválida (no existe, cerrada, etc).

EJEMPLO:

Código: (Pawn) [Seleccionar]
// Buffer de transmision.
new TxData[5] = {'H', 'e', 'l', 'l', 'o' }

// Enviar datos.
TcpServerSend(Id, TxData, 5)

// Forzar procesamiento de conexión, intentar enviar datos inmediatamente.
TcpServerProcessId(Id)

Nota: Si se necesita enviar muchos datos seguidos (muchas llamadas consecutivas a TcpServerSend()), se aconseja comprobar antes si fueron transmitidos previamente con TcpServerCheckTxPendingId(Id) o mediante el evento @OnTcpServerTx().
   

TcpServerGetMaxId()

Obtiene el numero máximo de conexiones permitidas en simultaneo por el servidor TCP/IP.

El valor retornado es idéntico al valor de la constante TCPSERV_MAX_CONNECTIONS, pero se recomienda utilizar esta función ya que la misma retorna el valor directamente desde el PLC, por lo tanto se actualiza con cada actualización de firmware, sin depender del entorno StxLadder.

RETORNO:

   - Número máximo de conexiones simultáneas admitidas por el servidor.

EJEMPLO-1:

Código: (Pawn) [Seleccionar]
   new Id
   new TxData[5] = {'H', 'e', 'l', 'l', 'o' }

   //
   // Recorrer todas la posibles conexiones y enviar datos en cada una.
   //

   for(Id=1; Id <= TcpServerGetMaxId(); Id++)
   {
      // Comprobar si la conexión no está cerrada.
      if(TcpServerCheckClosedId(Id) == 0)
      {
         // Transmitir datos en la conexión abierta.
         TcpServerSend(Id, TxData, 5)
      }
   }

EJEMPLO-2:

Código: (Pawn) [Seleccionar]
   new Id

   //
   // Recorrer todas la posibles conexiones y abortar todas.
   //

   for(Id=1; Id <= TcpServerGetMaxId(); Id++)
   {
      // Comprobar si la conexión no está cerrada.
      if(TcpServerCheckClosedId(Id) == 0)
      {
         // Abortar conexión.
         cpServerAbortId(Id)
      }
   }


TcpServerSetConnectedEvent()

Activa el evento @OnTcpServerConnected() que se llama cuando un cliente TCP se conecta inicialmente al servidor.

RETORNO:

   - (    0   ) = Éxito, evento activado.
   - (    -1  ) = Error, evento no activado.

EJEMPLO:

Código: (Pawn) [Seleccionar]
//
// Almacena identificadores de conexiones.
// Cada elemento contiene el identificador de conexión (mayor a 0).
// Si la conexión esta activa es un valor entero positivo mayor a 0.
// Si la conexión no está activa, el elemento vale 0.
//

new ConnId[TCPSERV_MAX_CONNECTIONS+1]

PlcMain()
{
   // ...

   // Activar evento para conexión de cliente.
   TcpServerSetConnectedEvent()
   
   // ...

}

@OnTcpServerConnected()
{
new Id

        // Obtener todos los Id con conexiones nuevas aceptadas.
while((Id=TcpServerGetNewId()) > 0)
{
                // Bienvenido!
     
// Actualizar Id en memoria con conexiones activas.
ConnId[Id] = Id
}
}

Nota: Luego podemos recorrer el array ConnId[] e identificar cuales conexiones esta activas.


TcpServerSetClosedEvent()

Activa el evento @OnTcpServerClosed() que se llama cuando un cliente TCP cierra la conexión al servidor.

RETORNO:

   - (    0   ) = Éxito, evento activado.
   - (    -1  ) = Error, evento no activado.

EJEMPLO:

Código: (Pawn) [Seleccionar]
//
// Almacena identificadores de conexiones.
// Cada elemento contiene el identificador de conexión (mayor a 0).
// Si la conexión esta activa es un valor entero positivo mayor a 0.
// Si la conexión no está activa, el elemento vale 0.
//

new ConnId[TCPSERV_MAX_CONNECTIONS+1]

PlcMain()
{
   // ...

   // Activar evento para cierre de conexión.
   TcpServerSetClosedEvent()
   
   // ...

}

@OnTcpServerClosed()
{
   new Id

   //
   // Recorrer todas la posibles conexiones.
   //
   
   for(Id=1; Id <= TcpServerGetMaxId(); Id++)
   {
   // Actualizar conexiones cerradas.
   if(TcpServerCheckClosedId(Id) == 0)
   {
                   // Adiós!
         
   ConnId[Id] = 0
   }    
   }
   
}
Nota: Luego podemos recorrer el array ConnId[] e identificar cuales conexiones esta activas.


TcpServerSetRxEvent()

Activa el evento @OnTcpServerRx() que se llama cuando datos son recibidos de un cliente TCP remoto.

RETORNO:

   - (    0   ) = Éxito, evento activado.
   - (    -1  ) = Error, evento no activado.

EJEMPLO:

Código: (Pawn) [Seleccionar]
// Buffer de recepción.
new RxData[10]

// Buffer de transmisión.
new TxData[5] = {'H', 'e', 'l', 'l', 'o' }

PlcMain()
{
   // ...

   // Activar evento para recepción de datos del cliente.
   TcpServerSetRxEvent()
   
   // ...

}

@OnTcpServerRx()
{
new Id
        new Len

//
// Obtener conexiones con datos sin leer.
//

while((Id=TcpServerGetUnreadId()) > 0)
{
// Leer datos.
Len = TcpServerRead(Id, RxData, 10)

//
                // Hacer algo con los datos recibidos en RxData[].
                // La cantidad de bytes leídos se almacena en la variable 'Len'.
                //
   
       // Responder con un mensaje usando el Id de la conexión que recibió los datos.
       TcpServerSend(Id, TxData, 5)
}
}

TcpServerSetTxEvent()

Activa el evento @OnTcpServerTx() que se llama cuando una conexión transmitió todos los datos pendiente.

RETORNO:

   - (    0   ) = Éxito, evento activado.
   - (    -1  ) = Error, evento no activado.

EJEMPLO:

Código: (Pawn) [Seleccionar]
// Buffer de transmisión.
new TxData[5] = {'H', 'e', 'l', 'l', 'o' }

PlcMain()
{
   // ...

   // Activar evento para fin de transmisión de datos del cliente.
   TcpServerSetTxEvent()
   
   // ...

}

@OnTcpServerTx()
{
new Id

// Obtener conexiones con datos transmitidos.
while((Id=TcpServerGetDataSentId()) > 0)
{
           // Transmitir nuevamente datos usando el Id de la conexión.
   TcpServerSend(Id, TxData, 5)
}
}


TcpServerClrConnectedEvent()
TcpServerClrClosedEvent()
TcpServerClrRxEvent()
TcpServerClrTxEvent()


Cada una desactiva los siguientes eventos (si fueron previamente activados):

@OnTcpServerConnected()
@OnTcpServerClosed()
@OnTcpServerRx()
@OnTcpServerTx()


RETORNO:

   - (    0   ) = Éxito, evento desactivado.


« Última Modificación: noviembre 27, 2015, 14:43:40 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1625
  • Soporte Técnico
Re:Servidor TCP
« Respuesta #9 : noviembre 23, 2015, 18:29:53 pm »
Cita de: Cristian
Buenas tardes Boris veo que en la línea que puse abajo mencionas que lee como máximo 10 bytes de la conexión, pero asumo que esto se da debido a que en el ultimo parámetro de la función pones 10, esto se puede modificar o conviene dejarlo asi?

"La linea "TcpServerRead(Id, RxData, 10)" lee como máximo 10 bytes de la conexión Id. Los datos son almacenados en el array RxData."

El valor 10 podes modificarlo, es la cantidad de bytes a leer. Puede ser mayor, hasta 70 bytes. Si hay menos bytes disponibles para leer, los restantes bytes se retornan con el valor 0. El array RxData[] debe tener el tamaño suficiente para almacenarlos.

El retorno de TcpServerRead() si es exitoso, devuelve la cantidad de bytes leídos.

En el mensaje anterior publique la descripción de cada función, te va a servir para conocer como usarlas.

Saludos
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

coloriginal

  • Aprendiz
  • **
  • Mensajes: 30
Re:Servidor TCP
« Respuesta #10 : noviembre 26, 2015, 19:14:35 pm »
Hola Boris, estuve probando con mi desarrollo la nueva función del TCP Server a lo cual me surgió un inconveniente, en una parte de mi código tengo un envió desde la pc hacia el PLC de unos paquetes que el PLC interpreta (proceso que es muy rápido) y los envía a una impresora térmica y luego de cada comando le envía un ok a la pc, hasta acá todo bien, el problema es que el PLC tarda bastante en devolver el ok (2 seg mas o menos) y por ende la impresión se demora mucho ya que al tener que confirmar la correcta impresión de cada línea se lleva mucho tiempo la impresión total. Incluso para descartar cualquier error en mi programación me base en tu ejemplo y en él se puede ver que al enviar un comando hay bastante demora hasta la respuesta del PLC.

Por favor decime si hay algo que se pueda hacer para agilizar este tema ya que no creo que sea una limitación del PLC debido a que he probado con micros mucho mas chicos (ARDUINO UNO + SHIELD W5001) y este mismo proceso lo resuelve casi instantáneamente.

Desde ya muchas gracias por cualquier aporte que me puedas dar.
A.S.: Cristian M. Colovatto
M. P. :3076
(0351)-152635979

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1625
  • Soporte Técnico
Re:Servidor TCP
« Respuesta #11 : noviembre 26, 2015, 20:49:01 pm »
Buenas tardes Cristian,

Te paso adjunto una actualización de firmware para tu placa, la versión 210.

Fíjate de actualizar y probar nuevamente, ya que tiene unas mejoras.

Por otro lado, te paso una captura de pantalla realizada con un capturador de paquetes Ethernet, con la respuesta de la placa transmitiendo continuamente la cadena "Hello" (cada cadena es transmitida cuando el evento @OnTcpServerTx() indica que los datos previos han sido transmitidos exitosamente, es decir el el cliente responde con ACK).

Fíjate que el tiempo entre que se envía la cadena desde la placa (IP 192.168.1.81) hasta que la computadora (cliente) responde con con un ACK (IP 192.168.1.15) es de 0.5 segundos (0.49 para se exactos). Te lo subraye con rojo a los tiempos de los paquetes para que lo veas.

Por lo tanto, si el problema persiste luego de actualizar el firmware, debes tener otro Delay en el medio, entre que imprimís con la impresora y envías al server. Corrobora por favor.

Avísame si mejoras.

Saludos
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

coloriginal

  • Aprendiz
  • **
  • Mensajes: 30
Re:Servidor TCP
« Respuesta #12 : noviembre 27, 2015, 05:04:38 am »
Muchísimas gracias por la pronta respuesta, apenas lo pueda probar estaré comentando los resultados.
A.S.: Cristian M. Colovatto
M. P. :3076
(0351)-152635979

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1625
  • Soporte Técnico
Re:Servidor TCP
« Respuesta #13 : noviembre 27, 2015, 14:26:41 pm »
Buenas tardes Cristian,

Acá te paso otra actualización de firmware con una función nueva: TcpServerProcessId()
Que te va a permitir enviar datos inmediatamente.

Pero antes debo explicarte como funciona el TCP en la placa.

El sistema por defecto procesa cada 0.5 segundos las conexiones activas, y de acuerdo a las condiciones de las mismas efectua alguna acción: transmite datos nuevos si hay pendientes por transmisión, cierra conexiones abortadas, actualiza timeouts, etc.

Esto no se aplica para paquetes que son recibidos, ellos son procesados inmediatamente y la respuesta interna es inmediata también.

Bajo este criterio, cuando envíes datos nuevos el sistema comenzará enviarlos como máximo en 0.5 segundos.

Por ejemplo, si en cualquier momento deseas usar TcpServerSend() el sistema puede tardar hasta 0.5 segundos en comenzar el envio.

El sistema es así para procesar eficientemente otras conexiones y realizar las demás operaciones del PLC (como adquisición de datos, procesamiento de código, etc).

En tu caso, lo ideal seria que el PLC compruebe la correcta impresión y luego envíe un OK a la PC, pero no por cada linea.
Sin embargo, a continuación explico como hacer la transmisión de forma inmediata para que tu proyecto funcione como lo hacías antes con tu otro sistema.

Solución para enviar inmediatamente:

En el caso que necesitemos enviar inmediatamente, antes de los 0.5 segundos, se puede utilizar la función que acabo de crear: TcpServerProcessId(Id)

La misma fuerza al sistema a realizar el procesamiento de la conexión activa Id inmediatamente, sin esperar a que sea procesada por el sistema.

Ejemplo:

Código: (Pawn) [Seleccionar]

// Buffer de transmision.
new TxData[5] = {'H', 'e', 'l', 'l', 'o' }

// Enviar datos.
TcpServerSend(Id, TxData, 5)

// Forzar procesamiento de conexión, intentar enviar datos inmediatamente.
TcpServerProcessId(Id)


Si necesitas enviar muchos datos seguidos (muchas llamadas consecutivas a TcpServerSend()), te aconsejo comprobar antes si fueron transmitidos previamente con TcpServerCheckTxPendingId(Id) o utilizar el evento @OnTcpServerTx().

Adjunto te paso una captura de pantalla (tcp_process_now.png) de datos Ethernet capturados de la placa, los mismos son enviados desde
la placa (192.168.1.81) a la PC (192.168.1.15) en 1 mS aproximadamente, desde que se envía hasta que la PC responde como recibido.

Instalación de la nueva función

Primero debes actualizar el firmware de la placa a la versión 211 con el archivo que te paso adjunto (archivo stx8081-d1-v211.sff).

Luego copiar el archivo: tcpserver.inc  que te adjunto en este mensaje en el <directorio de instalación StxLadder>\slicetex\StxLadder\pawn\include\common, que puede ser por ejemplo: C:\Program Files\slicetex\StxLadder\pawn\include\common. Quizás necesites permisos de administrador.

Eso te permite usar la nueva función desde StxLadder.
En el futuro, cuando actualice StxLadder a la próxima versión 1.7.1 la misma ya estará incluida.

Esta modificación soluciona el tema de velocidad que planteabas en tu proyecto.
« Última Modificación: noviembre 27, 2015, 14:33:58 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

coloriginal

  • Aprendiz
  • **
  • Mensajes: 30
Re:Servidor TCP
« Respuesta #14 : noviembre 30, 2015, 11:28:50 am »
Buenos días Boris, gracias por la rápida respuesta y las opciones para solucionar el inconveniente. Te comento que opte por atender tu sugerencia y responder una vez terminada la impresión para no complicar la implementación.

Aprovecho para comentarte que ya implemente casi todas las funciones que necesito y esta funcionando perfecto, voy manteniendo al tanto.

Gracias.
A.S.: Cristian M. Colovatto
M. P. :3076
(0351)-152635979