Problema con las últimas versiones (packed string)

  • 10 Respuestas
  • 4543 Vistas

PabloGa

  • Avanzado
  • ***
  • Mensajes: 103
Problema con las últimas versiones (packed string)
« : agosto 04, 2018, 20:05:27 pm »
Hola Boris que tal?

Hoy me dispuse a hacer una modificación al programa de mi PLC, y -como hago siempre- primero actualizo el StxLadder a la última versión disponible, y lo mismo con el firmware del PLC (el mío es un 8081-D2). Luego de la actualizaciòn tuve problemas; te paso la info:

Lo que tenía antes de actualizar era:
StxLadder 1.8.8
Firmware 227

Luego de actualizar pasé a:
Stxladder 1.9.2
Firmware 229

El problema se manifiesta así: al compilar el programa (ya con el nuevo entorno), me tira el siguiente error:

Error de Memoria: Insuficiente memoria RAM: El proyecto requiere 19668 bytes y el dispositivo tiene disponible 16384 bytes. Disminuya variables globales, variables locales inicializadas, comparta/reutilice variables globales, utilice packed strings, agrupe datos, etc.


Entonces voy a ver en el PLC qué marca, y en el display tiene el siguiente cartel:
PLC Return Code C:200 R:0

Pensé que habría un problema con el firmware, asi que lo volví para atrás a la V227. Pruebo a compilar con F6, y me da el mismo error. Entonces volví para atrás también el entorno StxLadder, y todo volvió a la normalidad (me apareció un cartel diciendo que el programa había sido construído con una versión de StxLadder superior, y que podría haber pérdidad de datos, pero seguí adelante y todo anduvo normal).

Aclaro que al grabar el firmware me aseguré de elegir la versión correcta del archivo, de acuerdo al modelo de PLC que uso: stx8081-d2.sff

En conclusión, no me queda claro si el problema está en el firmware o en el entorno.
Por lo pronto, tengo todo funcionando a la perfección, por lo que no hay ningún apuro en resolver nada.

Saludos y muchas gracias !
Pablo.
« Última Modificación: agosto 10, 2018, 18:55:07 pm por Soporte »

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 2324
  • Soporte Técnico
Re:Problema con las últimas versiones
« Respuesta #1 : agosto 04, 2018, 21:05:50 pm »
El problema se manifiesta así: al compilar el programa (ya con el nuevo entorno), me tira el siguiente error:

Error de Memoria: Insuficiente memoria RAM: El proyecto requiere 19668 bytes y el dispositivo tiene disponible 16384 bytes. Disminuya variables globales, variables locales inicializadas, comparta/reutilice variables globales, utilice packed strings, agrupe datos, etc.


Hola Pablo.

En las últimas versiones de firmware y StxLadder, se hace una correcta comprobación de memoria RAM utilizada antes de cargar el proyecto al PLC. Por lo tanto, quiere decir que tu código utilizaba más memoria de la permitida.

Esto en general no causa problemas porque es probable que justo no interacciones con otros sectores de RAM utilizado por el sistema operativo, pero si llegara a pasar, se te cuelga el PLC.

La solución en general es bajar la memoria RAM utilizada, que en tu caso, seguramente es por utilizar muchas cadenas/strings, ya que cada carácter consume 4 bytes en Pawn.

Lo que te aconsejo, es cargar la última versión de firmware y StxLadder, y compilar con la opción:

"Packed literal strings" , que se encuentra en "Proyecto > Propiedades > Compilador (pestaña)".



Seguramente, el porcentaje de RAM utilizada se te va reducir bastante, y te va a dar "Compilación correcta".

Sí lo compila (muy probable), tenés seguridad de que el PLC sea más estable respecto a la memoria utilizada RAM en tu proyecto.

La opción "Packed literal strings" hace que se agrupen "4" carácteres de una cadena, en una celda de 32-bits, ya que si esta opción se utiliza un carácter por celda, lo que es un desperdicio de memoria, porque 3 bytes quedan libres sin utilizar.

En general no necesitarias otro tipo de cambio en tu código, a menos que indexes en algún lugar una cadena, caracter por caracter, por ejemplo:

Código: (Pawn) [Seleccionar]
new String[]="Hola"

if(String[0]='H')
{
    // Letra H
}

Pero si solo operas con cadenas de forma normal, utilizando las funciones, no hay problemas (si debes actualizar firmware).

Sí utilizas la función StrFormat(), el tercer argumento debe ser "true" o "PACKED":

StrFormat(..., ..., true, "...", ...)

StrFormat(..., ..., PACKED, "...", ...)



En el link abajo, paso el POST donde se muestra el por qué de esta nueva característica de StxLadder, ya que en previas versiones había un calculo erróneo sobre la estimación de RAM utilizada por el proyecto y podía sobrepasar los límites admitidos.

http://foro.slicetex.com/index.php?topic=335.msg1805#msg1805

Además te da tips para disminuir uso de memoria RAM y utilizar "packed strings" .

Cualquier duda, avísame.

Saludos!









« Última Modificación: agosto 04, 2018, 21:24:23 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

PabloGa

  • Avanzado
  • ***
  • Mensajes: 103
Re:Problema con las últimas versiones
« Respuesta #2 : agosto 06, 2018, 12:36:39 pm »
Hola Boris buen día,

Muchas gracias por tus explicaciones.
La verdad es que tenía la sensación de que estaba super-holgado de memoria en mi PLC, pero evidentemente no es así (probablemente esté holgado de memoria flash para almacenar el programa en sí, pero jugado con la cantidad de RAM usada para variables).

Voy a tener que revisar bien el código antes de hacer cualquier upgrade de versiones, porque me parece que sí uso strings via subíndice en alguna parte, y me podría dar cualquier resultado. Fijate en las siguientes 2 funciones, que me parece que vos me las pasaste prehechas en algún momento, y las vengo utilizando. No tengo claro qué hacer con esas funciones para que sean compatibles con ese switch de compilación:

// ********************************************************************************
// Funcion     : ReemplazarEspacios()
// Descripcion : Al string que viene, se le reemplazan todos los ESPACIOS.
//
// ********************************************************************************

ReemplazarEspacios(const String[])
{
   new Buffer[30]
   new i=0
   
   // Hacer un lazo que parsea el string
   while(TRUE)
   {
      // Copiar una línea de String[] en Buffer[].
      if(String != ' ' && String != '\0')
      {
         Buffer = String
      }

      // Viene un ESPACIO en String ?
      if (String == ' ')
      {
         // Si, reemplazar por otro caracter
         Buffer = '_'
      }     
     
      // Fin de caracteres en String ?
      if (String == '\0')
      {
         Buffer = '\0'
         return Buffer
      }
      i = i+1
   }
}



// ********************************************************************************
// Funcion     : nLcdPrintMultLines()
// Descripcion : Imprime una cadena con múltiples líneas en VirtualHMI.
//               Soporta \n, que de otra manera no funciona
// ********************************************************************************

nLcdPrintMultLines(x, y, const String[])
{
   new Buffer[160]
   new i=0, j=0
   new Stop = FALSE
   
   // Parsear cadena.
   while(Stop == FALSE)
   {
      // Copiar una línea de String[] en Buffer[].
      while(String != '\n' && String != '\0')
      {
         Buffer[j++] = String[i++]
      }
     
      // Si hay carateres en Buffer[], imprimir.
      if (j != 0)
      {
         // Agregar terminador de fin de cadena.
         Buffer[j] = '\0'
         
         // Imprimir en VirtualHMI Buffer[] e incrementar numero de línea.
         nLcdPrintf(x, y, LCD_CLRLINE, "%s", Buffer)       
      }
     
      // Fin de caracteres en String[] ?
      if (String == '\0')
      {
         // Si, parar Loop.
         Stop = TRUE
      }
      else
      {
         // No, ajustar variables para próxima línea.
         j=0
         i++
         y++
      }
   }
}

Así como están ya no funcionarían, verdad ?
Gracias!
Pablo.

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 2324
  • Soporte Técnico
Re:Problema con las últimas versiones
« Respuesta #3 : agosto 07, 2018, 12:13:52 pm »
Buenos días Pablo.

La verdad es que tenía la sensación de que estaba super-holgado de memoria en mi PLC, pero evidentemente no es así (probablemente esté holgado de memoria flash para almacenar el programa en sí, pero jugado con la cantidad de RAM usada para variables).

En flash no creo que tengas inconveniente. Igual, la nueva versión de StxLadder te informa cuanto consume el proyecto en todos las áreas de memoria.

Voy a tener que revisar bien el código antes de hacer cualquier upgrade de versiones, porque me parece que sí uso strings via subíndice en alguna parte, y me podría dar cualquier resultado

Te adjunto una función de conversión que se llama MyUnpackString() y lo que hace es "desempaquetar" (unpack) un "packed string".

Luego la voy a incluir en el firmware, por eso por ahora el nombre es MyUnpackString().

Esto es para tener compatibilidad con código existente, donde es más facil el "parseo" con los string tipo "unpacked".

Por ejemplo, par usarlo, dentro de las funciones que me pasas haces:

Código: (Pawn) [Seleccionar]
ReemplazarEspacios(const PackedString[])
{
   new Buffer[30]
   new String[100]  // Nuevo.
   new i=0

   // Unpack "PackedString" en "String" para facilitar algoritmo.
   MyUnpackString(PackedString, 0, String, 0)

   // Resto igual ...
}

Código: (Pawn) [Seleccionar]
nLcdPrintMultLines(x, y, const PackedString[])
{
   new Buffer[100]
   new String[100]  // Nuevo.
   new i=0, j=0, c
   new Stop = FALSE
   
   // Unpack "PackedString" en "String" para facilitar algoritmo.
   MyUnpackString(PackedString, 0, String, 0)

   // Resto igual ...
}

Te adjunto el ejemplo funcional en el proyecto .ZIP que contienen la función MyUnpackString().



Lo que te recomiendo es hacer un "backup" del proyecto que funciona bien.

Luego pasar a StxLadder 1.9.2 y con la opción de compilación "Packed string", ver si compila y cuanta memoria RAM ahorraste.

Luego modificar con MyUnpackString() las funciones que indexan caracteres y probar el código.

También, muchas veces se declaran arrays globales y no se usan todo el tiempo en el programa, solo en forma temporal, por ahí fijate de optimizar, reutilizando arrays. Las variables que se inicializan en una función, cuentan como una variable global en cuanto a memoria RAM utilizada.



Hay otra forma que consiste en no utilizar la opción "Packed string" de compilación, y colocar el caracter "!" delante de cualquier string constante para hacerlo "packed" individualmente.

Ejemplo:

Código: (Pawn) [Seleccionar]
new String[] = !"Texto literal" // Packed.

nLcdPrintf(0, 0, LCD_CLRLINE, !"Hola mundo")  // Packed.

nLcdPrintf(0, 0, LCD_CLRLINE, !"%s", String)  // Packed.

Pero de esta forma debes ir linea por linea colocando el caracter "!" para ahorrar memoria, pero con la ventaja que controlas cuando no lo queres "packed" al string.

De esta forma, cada string que la antecede el símbolo "!" es "packed" y se ahorra memoria RAM, ya que cada caracter ocupa un byte de esta forma. Recordar que en Pawn, las cadenas literales (constantes) se almacenan en memoria RAM, no en ROM.

Saludos!
« Última Modificación: agosto 07, 2018, 12:25:56 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

PabloGa

  • Avanzado
  • ***
  • Mensajes: 103
Re:Problema con las últimas versiones
« Respuesta #4 : agosto 07, 2018, 14:40:20 pm »
Clarísimo ! Muchas gracias por la ayuda !
Ya voy a ver qué camino sigo.
Saludos !
Pablo.

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 2324
  • Soporte Técnico
Re:Problema con las últimas versiones (packed string)
« Respuesta #5 : agosto 10, 2018, 19:05:45 pm »
Hola Pablo.

Leyendo, encontré otra forma de manejar "packed string" de forma más natural en Pawn.

Asi como para indexar un string "unpacked" se utiliza "[ ]", para un "packed" string se puede utilizar corchetes "{ }".

Ejemplo:

Código: (Pawn) [Seleccionar]
new PackedString[] = !"Hola"

if(string{0} == 'H')
{
   // Primer caracter es letra "H" del Packed String.
}

new UnpackedString[] = "Hola"

if(string[0] == 'H')
{
   // Primer caracter es letra "H" del Unpacked String.
}

También es posible definir espacio para un string packed en cantidad de caracteres:

Código: (Pawn) [Seleccionar]
new PackedString[100 char]
El código anterior, definirá en memoria un array equivalente para 100 caracters, es decir 100/4=25 enteros de 32 bits.

Entonces la función nLcdPrintMultLines() la podes dejar como estaba antes, pero remplazando los [ ] por { } al indexar un Packed String.

Te adjunto el proyecto en .ZIP.

Código: (Pawn) [Seleccionar]
nLcdPrintMultLines(x, y, const String[])
{
   new Buffer[100 char] // Definir un string para 100 caracteres
   new i=0, j=0
   new Stop = FALSE
   
   // Parsear cadena.
   while(Stop == FALSE)
   {
      // Copiar una línea de String[] en Buffer[].
      while(String{i} != '\n' && String{i} != '\0')
      {
         Buffer{j++} = String{i++}
      }
     
      // Si hay carateres en Buffer[], imprimir.
      if(j != 0)
      {
         // Agregar terminador de fin de cadena.
         Buffer{j} = '\0'
         
         // Imprimir en VirtualHMI Buffer[] e incrementar numero de línea.
         nLcdPrintf(x, y++, LCD_CLRLINE, "%s", Buffer)
         
         // Agregar Delay para asegurar fin de transmisión.
         DelayMS(150)
      }
     
      // Fin de caracteres en String[] ?.
      if(String{i} == '\0')
      {
         // Si, parar Loop.
         Stop = TRUE
      }
      else
      {
         // No, ajustar variables para próxima línea.
         i++
         j = 0
      }
   }
}

Creo que esta forma te deja el código mejor si utilizás la opción de compilación "Packed string".

Saludos!
« Última Modificación: agosto 10, 2018, 19:08:27 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

PabloGa

  • Avanzado
  • ***
  • Mensajes: 103
Re:Problema con las últimas versiones (packed string)
« Respuesta #6 : agosto 12, 2018, 18:08:07 pm »
Hola Boris,

Impecable. Ya lo tengo andando.

Te cuento lo que hice, siguiendo tus indicaciones:

1) Actualicé firmware y StxLadder.
2) Modifiqué las 2 funciones que usaban direccionamiento a caracteres dentro de un string nLcdPrintMultLines() y ReemplazarEspacios(), cambiando los corchetes por llaves.

Con estos 2 cambios, compila OK, y la memoria consumida baja de 19668 bytes a 11640 (!!).

Pruebo a ejecutar, y todo parece funcionar bien, pero en un sitio donde muestro strings a través de VirtualHMI, no salen bien. Entonces recorro el fuente hasta encontrar todos los lugares donde haya StrFormat(), y cambio "false" por "true" (primero cambié por "packed", pero tiró error al compilar, entonces le puse "true").

Con esto último, aparentemente todo está funcionando bien de nuevo, con software actualizado a lo último.
Si algo no quedó bien, en los próximos días me voy a dar cuenta.

De paso. Debo esperar algún cambio o mejora derivado de las siguientes mejoras del firmware?:
      + Se amplia de 6 a 10 la cantidad de conexiones abiertas
        simultáneas TCP.
      + Se amplia de 12 a 20 la cantidad de puertos disponibles para
        escucha de paquetes TCP.
      + Se amplia de 2 a 4 la cantidad de conexiones abiertas
        simultáneas ModBus TCP (esto se conoce en documentación
        como parámetro "NumberMaxOfTransactions").

Muchas gracias por tu ayuda como siempre !
Saludos,
Pablo.

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 2324
  • Soporte Técnico
Re:Problema con las últimas versiones (packed string)
« Respuesta #7 : agosto 12, 2018, 18:27:12 pm »
Impecable. Ya lo tengo andando.

Perfecto Pablo!

Pruebo a ejecutar, y todo parece funcionar bien, pero en un sitio donde muestro strings a través de VirtualHMI, no salen bien. Entonces recorro el fuente hasta encontrar todos los lugares donde haya StrFormat(), y cambio "false" por "true" (primero cambié por "packed", pero tiró error al compilar, entonces le puse "true").

Probá con mayúsculas: PACKED

Con esto último, aparentemente todo está funcionando bien de nuevo, con software actualizado a lo último.
Si algo no quedó bien, en los próximos días me voy a dar cuenta.

A veces me llega un mail de reporte de "spam" con los mails que envías desde la placa, se me hace, por lo que veo, que se debe ser por poner en el "Subject" la fecha/hora sin ningún texto.

En el asunto podrías colocar algo como: "Notificacion - DDMMAAAA-HHMM"

Sí es que necesitas poner le fecha/hora en el asunto.

Para que parezca más normal.

Este es la copia del reporte:

Código: (Mail) [Seleccionar]
This message was created automatically by mail delivery software.

A message that you sent could not be delivered to one or more of its
recipients. This is a permanent error. The following address(es) failed:

  pXXXXX@gmail.com
    host outbound.mailspamprotection.com [108.163.220.50]
    SMTP error from remote mail server after end of data:
    550 High probability of spam

---------- Forwarded message ----------
From: PLC <plc.XXXXX@slicetex.com>
To: <pXXXXX@gmail.com>
Cc:
Bcc:
Date: Sat, 11 Aug 2018 21:21:29 -0000
Subject: 11/08/2018 - 21:21:22
RECONEXION ENERGIA
FASES=R S T
TANQUE PA=005  PB=000
ALARMA=DESARM-OFF
M.CALD=SMART  CONF=1
T.Ext=14.7C   T.Int=20.1C

--

PLC
pXXXX@gmail.com


Supongo que mientras te lo considere como spam, no lo debes estar recibiendo.

De paso. Debo esperar algún cambio o mejora derivado de las siguientes mejoras del firmware?:
      + Se amplia de 6 a 10 la cantidad de conexiones abiertas
        simultáneas TCP.
      + Se amplia de 12 a 20 la cantidad de puertos disponibles para
        escucha de paquetes TCP.
      + Se amplia de 2 a 4 la cantidad de conexiones abiertas
        simultáneas ModBus TCP (esto se conoce en documentación
        como parámetro "NumberMaxOfTransactions").

Nada que afecte el funcionamiento, debería mejorar la conectividad para aplicaciones con protocolo TCP, como ModBus TCP, webserver, mails, etc.

Saludos!
« Última Modificación: agosto 12, 2018, 18:33:02 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

PabloGa

  • Avanzado
  • ***
  • Mensajes: 103
Re:Problema con las últimas versiones (packed string)
« Respuesta #8 : agosto 12, 2018, 20:52:28 pm »
Hola Boris,

Muchas gracias de nuevo por tu excelente soporte.

Me quedan 2 consultas:

- El tema ese de los emails que te llegan "por rebote", cuando los emails enviados por mi sistema son tomados como spam. Es posible que sean enviados a otra dirección que no sea @slicetex.com ?? Es esto configurable?
De todas formas acabo de modificar el SUBJECT de los mails, como vos me indicaste, y espero que con esto ya no te lleguen más emails rebotados, pero la verdad es que este punto me dejó un tanto preocupado.

- La habilitación de los "Packed Strings" que ahora tengo implementada, tiene alguna consecuencia para la identificación de los bytes dentro del buffer de recepción de datos por UDP ? Concretamente yo tengo algo más o menos así:

@OnUdpRx()
{
      // Leer 10 bytes del array y almacenarlos en RxData[].
      UdpRxDataRead(RxData,0,10,false)

      // Y Luego voy extrayendo los datos que hay en cada byte de la trama UDP...
      if (RxData[0] == 122)

     etc.

Me parece que en esto no debería haber ninguna influencia porque son arrays, pero no strings...

Saludos !
Pablo.


Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 2324
  • Soporte Técnico
Re:Problema con las últimas versiones (packed string)
« Respuesta #9 : agosto 13, 2018, 11:03:03 am »
Buenos días Pablo.

- El tema ese de los emails que te llegan "por rebote", cuando los emails enviados por mi sistema son tomados como spam. Es posible que sean enviados a otra dirección que no sea @slicetex.com ?? Es esto configurable?
De todas formas acabo de modificar el SUBJECT de los mails, como vos me indicaste, y espero que con esto ya no te lleguen más emails rebotados, pero la verdad es que este punto me dejó un tanto preocupado.

No, ya que cuando usas SmtpInitSimple() se utiliza el server SMTP de Slicetex, y la protección anti-spam no es configurable en el server.

Las últimas versiones de firmware, permiten actualizar hora/fecha desde internet, es importante tener la hora/fecha correcta del sistema al momento de enviar emails, para que no sean sospechosos de "spam", fíjate en el siguiente post:

http://foro.slicetex.com/index.php?topic=321.0

- La habilitación de los "Packed Strings" que ahora tengo implementada, tiene alguna consecuencia para la identificación de los bytes dentro del buffer de recepción de datos por UDP ? Concretamente yo tengo algo más o menos así:

@OnUdpRx()
{
      // Leer 10 bytes del array y almacenarlos en RxData[].
      UdpRxDataRead(RxData,0,10,false)

      // Y Luego voy extrayendo los datos que hay en cada byte de la trama UDP...
      if (RxData[0] == 122)


No, porque lo que se modifica es la codificación de un string, que en vez de tomar un caracter cada 4 bytes, se utiliza un caracter por byte. Esto solo influye en los string que se almacenan en un array como "packed".

Saludos!
« Última Modificación: agosto 13, 2018, 11:09:57 am por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

PabloGa

  • Avanzado
  • ***
  • Mensajes: 103
Re:Problema con las últimas versiones (packed string)
« Respuesta #10 : agosto 13, 2018, 12:56:55 pm »
Clarísimo. Muchas gracias !