Article View: es.comp.os.linux.programacion
Article #9330Demasiado retardo leyendo de /dev/ttyS0
From: Jesús Ángel
Date: Sat, 27 Jul 2002 01:17
Date: Sat, 27 Jul 2002 01:17
349 lines
10765 bytes
10765 bytes
Hola a todos/as
Tengo un receptor GPS conectado al primer puerto serie. Este receptor
env�a una vez por segundo un mensaje con los datos de la posici�n.
He hecho un programa para leer los datos y mostrarlos por pantalla. El
problema es que mi programa muestr� los datos cada 9 segundos
(aproximadamente) en lugar de hacerlo cada segundo.
Para leer los datos utilizo E/S as�ncrona. Instalo un manejador para la
se�al SIGIO de forma que cada vez que recibo esta se�al leo un byte y lo
guardo en un buffer (rx_buf).
El problema est� en que s�lo leo 14 bytes cada segundo del puerto serie.
Como el mensaje que env�a el GPS tiene 128 bytes pues esto resulta en
los 9 segundos (aprox) que hay entre cada dos mensajes recibidos.
El manejador de la se�al es este:
void signal_handler_IO (int status)
{
read (fd, &buf[inicio++], 1);
if (inicio == MAX_BUF)
{
inicio = 0;
}
}
El c�digo est� basado en una versi�n suministrada por el fabricante de
la tarjeta para MSDOS. En este caso creo que utiliza interrupciones para
determinar cuando hay que leer un nuevo byte del puerto serie. La
funci�n es esta:
void __interrupt __far new_serial()
{
short status;
do{ // Get recieved data
status = inp(NCVPORT+IIR);
if(status & 0xF8){
CloseGPS();
break; // port has disappeared
}
if ((status & 6) == 4) rx_buff[head++] = inp(NCVPORT);
if ((status & 6) == 6)inp(NCVPORT+LSR); // Clear framing or parity errors
if ((status & 6) == 0)inp(NCVPORT+MSR);
if (head == max_buffer) head = 0;
}while(status & 4);
_disable();
outp(0x20,EOI);
_enable();
}
Como en el c�digo anterior parece (no he conseguido documentaci�n de
inp) que lee bytes del puerto serie mientras haya alguno, he modificado
mi manejador de se�al para que haga lo mismo:
void
signal_handler_IO (int status)
{
int res;
do
{
res = read (fd, &buf[inicio++], 1);
if (inicio == MAX_BUF)
{
inicio = 0;
}
}
while (res != 0);
}
En este caso leo los datos del puerto serie a toda pastilla.
El problema es que, como siempre hay algo que leer el
programa se queda indefinidamente en esta funci�n, metiendo datos sin
parar en buf.
�A alguien se le ocurre una opci�n intermedia que me permita leer los
datos a suficiente velocidad (m�s de 128 Bps) y que no se quede
bloqueado el programa en la funci�n de lectura?
El c�digo completo de mi programa (recortado) es este:
#include <time.h>
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>
#define BAUDRATE B9600
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* fuentes cumple POSIX */
#define FALSE 0
#define TRUE 1
#define BYTE unsigned char
#define MAX_BUF 1024
volatile int STOP = FALSE;
void signal_handler_IO (int status); /* definicion del manejador de segnal */
int wait_flag = TRUE; /* TRUE mientras no segnal recibida */
void signal_handler_INT (int status); /* definicion del manejador de segnal */
int exit_flag = FALSE; /* FALSE mientras no segnal recibida */
unsigned char msgbuff[300]; /* buffer local */
unsigned char buf[MAX_BUF + 1]; /* buffer de rx */
int inicio = 0;
int fd;
int get_byte (void);
int get_I16 (int);
int
main (void)
{
int i, rec_cnt, have_sync, data_len;
struct termios oldtio, newtio;
struct sigaction saio, saint; /* definicion de accion de segnal */
time_t t_old, t_new;
rec_cnt = 0;
have_sync = 0;
data_len = 10;
/* abre el dispositivo en modo no bloqueo (read volvera inmediatamente) */
fd = open (MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0)
{
perror (MODEMDEVICE);
exit (-1);
}
/* instala el manejador de segnal antes de hacer asincrono el dispositivo */
saio.sa_handler = signal_handler_IO;
sigemptyset (&saio.sa_mask);
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction (SIGIO, &saio, NULL);
/* para capturar ^C y cerrar todo antes de salir */
saint.sa_handler = signal_handler_INT;
sigemptyset (&saint.sa_mask);
saint.sa_flags = 0;
saint.sa_restorer = NULL;
sigaction (SIGINT, &saint, NULL);
/* permite al proceso recibir SIGIO */
fcntl (fd, F_SETOWN, getpid ());
/* Hace el descriptor de archivo asincrono (la pagina del manual dice solo
* O_APPEND y O_NONBLOCK, funcionara con F_SETFL...) */
fcntl (fd, F_SETFL, FASYNC);
tcgetattr (fd, &oldtio); /* salvamos conf. actual del puerto */
/*
*fija la nueva configuracion del puerto para procesos de entrada no canonica
* */
newtio.c_cflag =
BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD | PARENB | PARODD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
/* pone el modo entrada (no-canonico, sin eco,...) */
newtio.c_lflag = 0;
tcflush (fd, TCIFLUSH);
tcsetattr (fd, TCSANOW, &newtio);
/* bucle de espera para entrada. */
do
{
/* tratamos de sacar un nuevo byte de rx_buff */
printf("\aLeyendo nuevos bytes\n");
i = get_byte ();
if (i == -1)
continue; /* no hay nuevos bytes */
/* esperamos la cabecera del mensaje: 0xFF 0x81 */
if (!rec_cnt)
{
if ((i == 0xFF) & (!have_sync))
{
/* Primer byte de sincronismo */
have_sync = 1;
continue;
}
if (i == 0x81)
{
/* segundo byte de sincronismo */
if (have_sync)
{
rec_cnt += 2;
/* reconstruimos la cabecera */
*(int *) (msgbuff) = 0x81FF;
}
}
have_sync = 0;
continue;
}
/* ya tenemos la cabecera, guardamos los bytes del msg */
if (rec_cnt)
{
msgbuff[rec_cnt++] = (BYTE) i; /* Byte de datos */
if (rec_cnt == 6)
{
/* obtenemos el numero de bytes del mensaje */
i = get_I16 (3); /* palabras en el mensaje */
data_len = 2 * i + ((i > 0) ? 12 : 10);
}
if (rec_cnt < data_len)
{
continue; /* seguimos hasta recibir todos los bytes del msg */
}
}
/* aqui se comprobaria el Cs de cabecera y datos */
/* aqui se procesaria el msg recibido */
/* calculamos cuanto tarda en cada pasada (nuevo mensaje) */
/* NOTA: el primer valor no sirve */
t_new = time (NULL);
printf ("Intervalo entre actualizaciones: %d\n", (int) (t_new - t_old));
fflush (stdout);
t_old = t_new;
/* me preparo para rx el siguiente msg */
rec_cnt = 0;
data_len = 10;
}
while (exit_flag == FALSE);
/* restaura la configuracion original del puerto */
tcsetattr (fd, TCSANOW, &oldtio);
exit (1);
}
/***************************************************************************
* * recoge un byte nuevo del buffer de recepci�n. Si no hay ning�n nuevo *
* * byte disponible, devuelve -1 *
* ***************************************************************************/
int
get_byte ()
{
int byte;
static unsigned int indice = 0;
if (indice == inicio)
{
return (-1); /* no hay nuevos bytes recibidos */
}
byte = buf[indice];
indice++;
if (indice == MAX_BUF)
{
indice = 0; /* volvemos al principio */
}
return (byte);
}
/***************************************************************************
* * Get A 2 Byte Integer From Message Buffer *
* ***************************************************************************/
get_I16 (int i)
{
int iv;
i--;
i *= 2; // convert to bytes
iv = *(BYTE *) (msgbuff + i + 1);
iv = iv << 8;
iv |= *(BYTE *) (msgbuff + i);
return iv;
}
/***************************************************************************
* * manipulacion de segnales lee datos de /dev/ttyS* mientras est�n
* disponibles.
* ***************************************************************************/
void
signal_handler_IO (int status)
{
int res;
do
{
res = read (fd, &buf[inicio++], 1);
if (inicio == MAX_BUF)
{
inicio = 0;
}
}
while (res != 0);
}
/***************************************************************************
* * manipulacion de segnales. pone exit_flag a TRUE, para indicar al bucle *
* * anterior que el usuario quiere detener el programa *
* ***************************************************************************/
void
signal_handler_INT (int status)
{
exit_flag = TRUE;
printf ("\nDetectada SIGINT, saliendo...\n");
}
--
Jes�s �ngel del Pozo Dom�nguez
Valladolid __�
GnuPG key-id: 0x17FB6CCE _ \<_
http://www.tel.uva.es/~jpozdom (_)/(_)
.--.
|o_o | Usuario Registrado
|:_/ | Linux: #168206
// \ \ http://counter.li.org
(| | )
/'\_ _/`\
\___)=(___/
Technical Details
Message-ID:
<slrnak3ttd.er2.jpozdom@sol.linux.bogus>Path:
arc1-ca.pugleaf.net!archiver1.google.com!news1.google.com!newsfeed.stanford.edu!news.tele.dk!small.news.tele.dk!212.43.194.69!fr.clara.net!heighliner.fr.clara.net!proxad.net!news-hub.cableinet.net!blueyonder!btnet-peer!btnet!newsfeed.bt.es!news.bt.es!not-for-mailShow Full Headers
Complete Article Headers
X-Google-Language: SPANISH,ASCII X-Google-Thread: f86c8,2c60a9ff9034469,start X-Google-Attributes: gidf86c8,public X-Google-ArrivalTime: 2002-07-26 18:32:45 PST Path: arc1-ca.pugleaf.net!archiver1.google.com!news1.google.com!newsfeed.stanford.edu!news.tele.dk!small.news.tele.dk!212.43.194.69!fr.clara.net!heighliner.fr.clara.net!proxad.net!news-hub.cableinet.net!blueyonder!btnet-peer!btnet!newsfeed.bt.es!news.bt.es!not-for-mail From: Jesús Ángel <jpozdom@ribera.tel.uva.es> Newsgroups: es.comp.os.linux.programacion Subject: Demasiado retardo leyendo de /dev/ttyS0 Date: 27 Jul 2002 01:17:41 GMT Organization: Sitio privado Lines: 349 Message-ID: <slrnak3ttd.er2.jpozdom@sol.linux.bogus> NNTP-Posting-Host: 213.254.77.86 Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit X-Trace: titan.bt.es 1027732661 27094 213.254.77.86 (27 Jul 2002 01:17:41 GMT) X-Complaints-To: abuse@bt.es NNTP-Posting-Date: 27 Jul 2002 01:17:41 GMT User-Agent: slrn/0.9.7.2 (Linux)