From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Discusiones sobre Productos NI

cancelar
Mostrando los resultados de 
Buscar en lugar de 
Quiere decir: 

¿Cómo manejar velozmente un rs 422 en labwindows cvi8?

Hola,

 

 

Os escribo porque tengo un problema con el manejo de la linea serie, mi programa con labwindows debe recibir un comando (un grupo de bytes) cada pocos ms, y he comprobado que no es capaz de hacerlo, es decir si le mando 1000 msgs recibe unos 800-900.

 

Tengo configurado el puerto serie así con un:

   InstallComCallback (COMPORT, EVENT_MASK, NOTIFY_COUNT, EVENT_CHAR, COM_CALLBACK, NULL); 

 

donde recibo los mensajes es así:

 

void COM_CALLBACK(int COMport, int EVENT_MASK, void *callbackdata)
{
  if (EVENT_MASK & LWRS_RXFLAG)
  {
     BYTES_READ = ComRd (COMport,READ_DATA,GetInQLen(COMport));  
     if (FIRST_TIME == 1)
     {
  SetCtrlVal (PANEL_HANDLE, SERIAL_TBOX_SYSTEM_VERSION, PREAD_DATA);
  SetCtrlVal (PANEL_HANDLE, SERIAL_STATUS_LED, 1);
  FIRST_TIME = 0;
    }
    if (IS_FULL_MESSAGE(PREAD_DATA))
    {
  FlushInQ(COMport);
  SIMULATION_DATA.RECEIVED_MESSAGES++;
  UPDATE_RECEIVED_MESSAGES();
  TREAT_MESSAGE(PREAD_DATA);
    }
 } 
}
Pensé en una especie de estructura con un doble buffer, es decir mientras recibe un mensaje puedas ir tratando el que ya tienes sin necesidad de interrumpir.
Y otra cuestión que tengo es, como puedo hacer para que sepa que he recibido 12bytes, 20bytes o 20bytes (tamaños de los mensajes) (notify count no se puede mofidicar en tiempo de ejecucion) sin tener que usar LWRS_RXFLAG, lo tengo puesto provisionalmente porque no puedo meter un caracter inventado por mi.
Muchas gracias por vuestro tiempo.

 

0 kudos
Mensaje 1 de 14
3.233 Vistas

Creo que tengo más preguntas que respuestas...

 

Normalmente el LWRS_RXFLAG se utiliza cuando el dispositivo remoto siempre envia mensajes con un terminator (por ejemplo el retorno de carro - 0x13 - u otro que esté especificado en la documentación del dispositivo). En este caso, la callback corre solamente cuando aquél particular carácter esté presente en al buffer. Esto es muy útil para dividir automaticamente los mensajes sin necesidad de manejarlos posteriormente. En tu caso no dices si hay tal carácter no como tienes configurado el programa, por lo que no tenemos datos suficientes para ayudarte. Y aquí voy con las preguntas:

 

¿Cómo has definido EVENT_MASK, NOTIFY_COUNT y EVENT_CHAR?

¿Tienes más que una com callback instalada? Si solo tienes una el test if (EVENT_MASK & LWRS_RXFLAG) en la callback es inútil ya que siempre la condición será verificada.

¿Cuánto tiempo larga la elaboración de los datos recibidos? (supongo que en UPDATE_RECEIVED_MESSAGES y TREAT_MESSAGE). Si la elaboración ocupa mucho tiempo es correcto pensar en separarla de la recepción en la com, posiblemente con un thread separado.

 

Para volver a lo que te decía anteriormente, no entiendo porque dices que tienes puestos el LWRS_RXFLAG provisionalmente: si el dispositivo envía mensajes con terminador no deberías necesitar medir la longitud de ellos, ya que la callback debería dividirlos automaticamente. Y aquí volvemos a que faltan datos para dar un respuesta definitiva...

 



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 kudos
Mensaje 2 de 14
3.226 Vistas

Lo he definido como sigue.

 

int NOTIFY_COUNT = 0;    (no me sirve para identificar diferentes longitudes)
int EVENT_CHAR = 10;     (el terminator PROVISIONAL)

 

EVENT_MASK = LWRS_RXFLAG; 

 

 

Mis mensajes no tienen terminator (ahora mismo si, ya que lo uso para debug, pero mas adelante no tienen que tenerlo), por eso me gustaría saber como saber, válgame la redundacia que llega un mensaje nuevo, éstos tienen diferentes longitudes y a priori no encuentro una solución ya que si uso el evento RXCHAR, como dice en la ayuda no siempre interrumpe cuando llega un byte nuevo, ya que trabajo a una elevada velocidad.

 

La elaboración (UPDATE Y TREAT) no tarda nada pues es copiar a un array auxiliar,de hecho comenté estos 2 métodos para ver si era la elaboración lo que perdía los mensajes, solo puse un contador para contar lso mensajes recibidos y aun así se pierden.

 

Muchas gracias por tu atención.

0 kudos
Mensaje 3 de 14
3.225 Vistas

Lo he definido como sigue.

 

int NOTIFY_COUNT = 0;    (no me sirve para identificar diferentes longitudes)
int EVENT_CHAR = 10;     (el terminator PROVISIONAL)

 

EVENT_MASK = LWRS_RXFLAG; 

 

 

Mis mensajes no tienen terminator (ahora mismo si, ya que lo uso para debug, pero mas adelante no tienen que tenerlo), por eso me gustaría saber como saber, válgame la redundacia que llega un mensaje nuevo, éstos tienen diferentes longitudes y a priori no encuentro una solución ya que si uso el evento RXCHAR, como dice en la ayuda no siempre interrumpe cuando llega un byte nuevo, ya que trabajo a una elevada velocidad.

 

La elaboración (UPDATE Y TREAT) no tarda nada pues es copiar a un array auxiliar,de hecho comenté estos 2 métodos para ver si era la elaboración lo que perdía los mensajes, solo puse un contador para contar lso mensajes recibidos y aun así se pierden.

 

Muchas gracias por tu atención.

0 kudos
Mensaje 4 de 14
3.225 Vistas

Un comentario y una pregunta.

 

Es correcto poner NOTIFY_COUNT = 0 ya que este parámetro no es usado en el caso del LWRS_RXFLAG.

 

Cómo sabes que tienes un mensaje nuevo? Si los mensajes tiene diferente longitud debe estar prevista una forma de identificarlos dentro del mensaje. Una alternativa podría ser que el mensaje tenga un encabezamiento diferente: si este encabezamiento es un carácter solo lo puedes utilizar como trigger del LWRS_RXFLAG.

 

Si no tienes más remedio podrías pensar en una estructura con un thread separado que lee el puerto serial y pone los caracteres recibidos en una TSQ (thread-safe queue). En el thread principal puedes leer la TSQ en bloques y manejar los mensajes: dividirlos y hacer lo que se necesite.



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 kudos
Mensaje 5 de 14
3.221 Vistas

Un mensaje se diferencia de otro, porque los 2 primeros bytes de cada mensaje son el ID de cada mensaje (esos ID ya están definidos).

 

La segunda parte no me entere muy bien, perdona, pero llevo poco tiempo trabajando con el puerto serie y con labwindows, ¿podrías ser un poco más especifico?

0 kudos
Mensaje 6 de 14
3.219 Vistas

Podrías realizar algo semejante; estoy asumiendo que los mensajes sono textos sin terminación, y que puedo usar las herramientas de texto para manejarlos (strlen). Si los mensajes son binarios y pueden incluir caracteres NUL (0x0) esto no se puede hacer.

 

while (1) {
    // read available com messages
    ComRd (1, buf, GetInQLen (1));

    // use ascii characters of id to discriminate messages
    id = (buf[0] << 😎 + buf[1];
    switch (id) {
        case 0x3031: len = 12; break;
        case 0x3032: len = 16; break;
        case 0x3033: len = 22; break;
        default: goto loop;       // unrecognized message: what to do?
    }


    // check to see if the message is complete:

    // if so copy it to a temporary buffer and send to the

    // use function to handle it, then discard it from the buffer

    if (strlen (buf) >= len) {

 

 

        // Send message to the user function
        StringCopyMax (msg, buf, len + 1);
        UserFunction (msg);

 

        // Eliminate message from the buffer
        StringCopyMax (buf, buf + len, strlen (buf) - len);
    }

 

loop:    ;
}

 

En este código falta la gestión de los errores en el puerto serial y alguna provisión por el caso que se pierda el síncrono entro el dispositivo y el programa: como ves estoy buscando el ID del mensage al comienzo del buffer, y si tienes un mensaje no reconocido la función simplemente sigue iterando en esto sin hacer nada; lo que hacer depende de la estructura de los mensajes: puedes poner un timeout y después ir buscando otro mensaje más adelante en 'buf' eliminando lo que hay anteriormente. Mucho depende del hecho que el ID sea único, esto es no puede pasar que en algun mensaje haya una secuencia de caracteres igual al ID de un mensaje.

 

No he utilizado los threads ya que si no tienes mucha experiencia en CVI es mejor utilizar estructuras más simples.



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 kudos
Mensaje 7 de 14
3.217 Vistas

Los mensajes son binarios, pero supongo que las diferencias serán menores, solo debo omitir el trabajo con las herramientas de texto y fabricar yo algunas, que no ignoren los NULL. Esta estructura lee continuamente el puerto serial verdad?, si no llega nada, simplemente dice que los caracteres leidos son 0 cierto?, el programa no se quedaria colgado o si?, por lo tanto un installComCallback no seria necesario?, si pongo este en el mismo hilo que la interfaz grafica esto se bloquearia?, no deberia porneal en otro hilo?. La funcion que tengo hecha para enviar mensajes, si que lo tengo hecho en otro hilo puesto que, como envia comandos a una velocidad muy alta me bloqueaba la interfaz de usuario y tengo que estar modificando valores en esta continuamente, lo tengo a nivel muy básico.

 

 

Muchísimas gracias por tu atención y por tu ayuda Roberto.

0 kudos
Mensaje 8 de 14
3.213 Vistas

Perdon, no sé en qué pensaba cuando escribì aquellas lìneas!

Claro que el sistema va a colgarse si pones este loop en una callback cualquiera u en el main!

Lo mejor es que pongas el còdigo en la callback de un timer que corra cada 5-10 ms, omitiendo el while y poniendo la variable 'buf' come static para que no se pierda el contenido de una ejecuciòn a otra.

Para manejar los mensajes binarios debes de acumular el nùmero de caractreres leìdos en una variable, utilizarla en vez del strlen () y quitae el nùmero de caracteres transferidos cada vez a la routina que los maneja.



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 kudos
Mensaje 9 de 14
3.210 Vistas

En resumen a ver si me he enterado bien, la función que comprueba si tengo mensajes se ejecuta cada 5-10ms(puede por lo tanto que tenga en la cola de entrada 1,2,3,7..mensajes), en ese tiempo miro si tengo mensajes si los tengo los trato, si no, simplemente salgo y espero a que ocurra todo el ciclo otra vez. ¿estoy en lo cierto?

0 kudos
Mensaje 10 de 14
3.208 Vistas