Pregunta

Te envío / recepción de datos a través de una línea serie en Linux y me gustaría encontrar el retardo entre caracteres.

Modbus utiliza un retardo de 3,5 caracteres para detectar límites de la trama de mensaje. Si hay más de un retardo de 1,5 personaje, el telegrama se declaró incompleta.

Estoy escribiendo un programa rápido en C, que es básicamente

fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
// setup newtio
....
tcsetattr(fd, TCSANOW, &newtio);
for(;;) {
    res = read(fs, buf, 1);
    if (res > 0) {
        // store time in milliseconds?
        //do stuff
    }
}

¿Hay alguna manera de medir el tiempo aquí? ¿O tengo que mirar a la recuperación de datos desde la línea de serie de una manera diferente?

También he intentado enganchar en SIGIO para obtener una señal cada vez que hay datos, pero me parece que obtener datos de 8 bytes a la vez.

(sí, sé que existen algunas bibliotecas Modbus pero quiero utilizar esto en otras aplicaciones)

¿Fue útil?

Solución

Modbus es como un montón de viejos protocolos y realmente odia hardware moderno.

La razón por la que está recibiendo 8 bytes a la vez es: Su PC tiene una serie FIFO (al menos) de 16 bytes de recibir y transmitir, en el hardware. La mayoría son 64byte o más grande.

es posible decir que el dispositivo UART el tiempo de espera y emitir una interrupción después de haber recibido un número de veces de carbonilla.

El nivel de disparo es ajustable, pero el conductor de bajo nivel establece que "inteligentemente". probar el modo de baja latencia usando setserial) Se puede jugar con el código en el controlador serie si es necesario. Google él (madurar la advertencia de contenido) no es bastante.

por lo que la rutina es como pseudocódigo

int actual=read (packet, timeout of 1.5 chars)

look at actual # of received bytes

if less than a packet, has issues, discard.

no es muy bueno.

Otros consejos

La respuesta es simple ... no puede (no sin escribir es el propietario controlador serie)!

Si usted está escribiendo un MODBUS principal Hay cierta esperanza: puede detectar el final de una respuesta del esclavo al esperar cualquier cantidad de tiempo (siempre que tenga más de 3,5 caracteres) sin recibir nada (select (2) puede ayudar aquí), o mediante el análisis de la respuesta sobre la marcha, como lo lee (el segundo método desechos mucho menos tiempo). También hay que tener cuidado que esperar al menos 3.5 caracteres de tiempo antes de mirar a transmitir una nueva petición, después de recibir la respuesta a la solicitud anterior. "Al menos" es clave aquí! Esperar más no importa. Esperando menos lo hace.

Si una escritura de un MODBUS esclavo a continuación que estés de suerte . Simplemente no pueden hacerlo fiable en el espacio de usuario de Linux. Usted tiene que escribir es el propietario controlador serie.

Por cierto, esto no es culpa de Linux. Esto es debido a la torpeza increíble de encuadre método de MODBUS.

Creo que va de este por el camino equivocado. Hay una construida en el mecanismo para asegurar que los caracteres vienen en todos juntos.

Básicamente, usted va a querer utilizar ioctl() y establecer los parámetros VMIN y VTIME adecuadamente. En este caso, parece que te gustaría VMIN (número mínimo de caracteres en un paquete) que se 0 y VTIME (cantidad mínima de tiempo permitido entre caracteres a 15 (son décimas de segundo).

Algunos realmente código básico ejemplo:

struct termio t;
t.c_cc[ VMIN ] = 0;
t.c_cc[ VTIME ] = 15;
if (ioctl( fd, TCSETAW, &t ) == -1)
{
    printf( msg, "ioctl(set) failed on port %s. Exiting...", yourPort);
    exit( 1 );
}

Haga esto antes de su open() pero antes de su read(). Aquí hay un par de enlaces que he encontrado tremendamente útil:

Programación de serie Guía

Comprender VMIN y VMAX

Espero que al menos ayuda a / que apunta en la dirección correcta, incluso si no es una respuesta perfecta para su pregunta.

No se pueden utilizar los tiempos de espera. En velocidades de transmisión más altas 3.5 tiempo de espera carácter significa unos pocos milisegundos, o incluso cientos de microsegundos. Tales tiempos de espera no se pueden manejar en el espacio de usuario de Linux.

En el lado del cliente, no es un gran problema ya Modbus no envía mensajes asíncronos. Por lo que es hasta que no permite enviar mensajes consecutivos dentro de 2 tiempo de espera de 3,5 caracteres.

En el lado del servidor, el problema es que si sus clientes tienen un tiempo extremadamente corto tiempo de espera de respuesta y Linux es demasiado ocupado no se puede escribir una solución encuadre a prueba de balas. Existe la posibilidad de que la función de lectura () devolverá más de un paquete. Aquí es (un poco artificial) ejemplo.

  1. cliente escribe un paquete al servidor. Tiempo de espera es digamos 20 ms.

  2. Digamos que Linux es en este momento muy ocupado, por lo que el kernel no se despierte el hilo dentro de los siguientes 50 ms.

  3. Después de 20 ms cliente detecta que no ha recibido ninguna respuesta por lo que envía otro paquete al servidor (tal vez resentir la anterior).

  4. función
  5. Si Linux despierta el hilo lectura después de 50 ms, read () se puede obtener 2 paquetes o incluso 1 y media dependiendo de cuántos bytes fueron recibidos por el controlador de puerto serie.

En mi aplicación que utiliza un método sencillo que intenta analizar bytes en la marcha - primera detección del código de función y luego trato de leer todos los bytes restantes para una función específica. Si consigo un millón y medio de paquetes que analizo sólo el primero y los bytes restantes se dejan en la memoria intermedia. Si vienen más bytes dentro de un corto tiempo de espera de los agrego y tratar de analizar, de lo contrario tirarlos a la basura. No es una solución perfecta (por ejemplo, algunos sub-códigos para la función 8 no tiene un tamaño fijo), pero desde Modbus RTU no tiene ningún carácter STX ETX, es el mejor que fuera capaz de averiguar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top