🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: es.comp.os.linux.programacion
Article #9330

Demasiado retardo leyendo de /dev/ttyS0

#9330
From: Jesús Ángel
Date: Sat, 27 Jul 2002 01:17
349 lines
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-mail

Show 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)