C Оптимизация алгоритма чтение данных с компорта (Требуется помощь в оптимизации алгоритма чтения данных с компорта)

Модератор: Модераторы разделов

TIT0
Сообщения: 11

C Оптимизация алгоритма чтение данных с компорта

Сообщение TIT0 »

Здравствуйте уважаемые. Я хочу попросить вас помочь мне в оптимизации моей программки для чтения данных с ком порта. На данный момент меня не устраивает сам алгоритм который я использую в программе для чтения, так как он использует циклы которые грузят процессор до 5-6% что является не оптимальным. Не могли бы вы мне помочь изменить алгоритм.
Скорость ком порта 4800 режим 8N1 пакет состоит из 16 байт вида CADR01234567891011. Пакеты приходят каждые 0.1 секунд. У меня проблема в том чтобы оптимально собрать его(пакет) в массив с которым я мог бы дальше работать в программе. Если вы подскажете мне как это сделать, я буду вам очень благодарен.

Привожу текст моей программы:
Функция read_device (читает данные с ком порта)

Код: Выделить всё

char read_device(fd,ch)
{
   unsigned char s[1];
   int nBytes;

   nBytes = read(fd, s, sizeof(s));
   if(nBytes>0){    // если прочитали нормальные данные то вернем их
      ch=s[0];
      return ch;
   }


   return 0; // иначе вернем 0

}


Функция main

Код: Выделить всё

int main(int argc, char** argv)
{
  int speed = 4800,rBytes;
  unsigned char ch,devname[256];



  filelog=fopen("MVS_logfile.txt","w");    // создаем лог файл
  if(!filelog){
     printf("Cant create file with logs!\n");
     exit(1);
  }
  ////////////////////////////////////////////////
  strcpy(devname, "/dev/ttyUSB0");

  int c, fd, cfd;
  if (argc > 1) {    // открываем девайс
    while (1) {
      c = getopt (argc, argv, "d:s:");
      if (c == -1)
    break;
      switch (c) {
      case '\0':
    fprintf(stderr,"Error: Unknown command ");
    print_help ();
    return -1;
      case 'h':
    print_help ();
     return 0;
    break;
      case 's':
    speed = atoi(optarg);
    break;
      case 'd':
    strcpy (devname, optarg);
    break;
      default:
    print_help ();
    return 0;
      }
    }
  }
  set_signal ();
  if( (fd = opendevice(devname, speed)) < 0) {
    fprintf(stderr,"FATAL ERROR: Can not open %s\n",devname);
    exit(-1);
  }
  }


///////////// Start read device /////////////////////////////
  while((!stop))
  {
    ch=read_device(fd,ch);

    if(ch=='R'){ // выбираем данные каналов из потока
      for(rBytes=0;rBytes<12;rBytes++){    // читаем 12 байт данных из потока
    ch=read_device(fd,ch);
    if(ch!=0)
      databuf[rBytes]=ch;        // если read_device вернула не 0, пишем байт в массив данных
    else{
      usleep(6200);                      // спим
      rBytes--;                              // вычитаем индекс массива так как 0 нам не нужен
    }
      }

      crtfile(databuf,rBytes,&filelog);

      printf("%x %x %x %x %x %x %x %x %x %x %x %x\n",databuf[0],databuf[1],databuf[2],databuf[3],databuf[4],databuf[5],databuf[6],databuf[7],databuf[8],databuf[9],databuf[10],databuf[11]);
    }

  }


  closedevice(fd);
  fclose(filelog);


  return 0;
}


Функции остановки программы

Код: Выделить всё

void
sig_handler (int sig)
{
  stop = 1;
}


void set_signal ()
{
  signal (SIGTERM, sig_handler);
  signal (SIGQUIT, sig_handler);
  signal (SIGKILL, sig_handler);
  signal (SIGINT, sig_handler);
  signal (SIGSTOP, sig_handler);
}



Настройка ком порта

Код: Выделить всё

int opendevice(char* device, int speed)
{
  struct termios new;
  speed_t sspeed;
  int res = 0, fd = 0;
  if(( fd = open(device, O_RDWR | O_NDELAY | O_NOCTTY)) < 0){
    perror("Can not open device");
    return -1;
  }
  //ttyUSBx settings

         sspeed = B4800;

  memset (&new, 0, sizeof (new));
  cfmakeraw(&new);
  new.c_cflag &= ~PARENB; // parent bit
  new.c_cflag &= ~CSTOPB;
  new.c_cflag &= ~CSIZE; // 1 stop bit
  new.c_cflag  = CS8;     // 8bit data
  new.c_cflag |= CREAD;  // Enable Receiver
  new.c_cflag |= CLOCAL; // Ignore modem control lines.
  new.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  new.c_oflag &= ~OPOST;
  new.c_cc[VMIN] = 1;    // 1 simbols for read
  new.c_cc[VTIME] = 1;    // Time of reading of 1 symbol


  res = cfsetispeed(&new, sspeed); //baud rate 4800
  if (res<0){
    perror("Can not set speed of device");
    return -1;
  };


  tcflush(fd, TCIOFLUSH);
  res = tcsetattr(fd, TCSAFLUSH, &new);
  if (res<0){
    perror("Can not set attribute to device");
    return -1;
  };
  return fd;
}
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: C Оптимизация алгоритма чтение данных с компорта

Сообщение eddy »

Используйте неблокирующий ввод/вывод и select/poll.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
TIT0
Сообщения: 11

Re: C Оптимизация алгоритма чтение данных с компорта

Сообщение TIT0 »

А можно поподробнее?
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: C Оптимизация алгоритма чтение данных с компорта

Сообщение eddy »

Открываем:

Код: Выделить всё

void tty_init(){
        if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0)
                die("Can't use port %s\n",comdev);
        ioctl(comfd,TCGETA,&oldtty); // Узнаем текущие параметры порта
        tty = oldtty;
        tty.c_lflag    = 0;
        tty.c_iflag    = BRKINT;
        tty.c_oflag    = 0;
        tty.c_cflag    = B9600|CS8|CREAD|CLOCAL|PARENB;
        tty.c_cflag &= ~PARODD;
        tty.c_cc[VMIN] = 0;
        tty.c_cc[VTIME] = 1;
        ioctl(comfd,TCSETA,&tty);
}

Читаем:

Код: Выделить всё

int read_tty_raw(){ // считываем 1 байт (с ожиданием сигнала)
        unsigned char rb; // то, что считываем
        fd_set rfds; // набор файловых дескрипторов
        struct timeval tv; // время ожидания
        int retval; // возвращаемое ф-й select значение
        tty.c_iflag &= ~PARODD; // принимаем с девятым битом = 0
        ioctl(comfd,TCSETA,&tty);
        FD_ZERO(&rfds); // очищаем набор
        FD_SET(comfd, &rfds); // теперь это - свойства порта
        tv.tv_sec = 0; tv.tv_usec = 50000; // ждем .05с
        retval = select(comfd + 1, &rfds, NULL, NULL, &tv);
        if (!retval){
                MSG("Контроллер не готов!\n");
                return (-1); // если сигнала нет, возвращаем ноль
        }
        if(FD_ISSET(comfd, &rfds)){
                if(read(comfd, &rb, 1) < 1){
                        MSG("Ошибка считывания\n");
                        return (-1); // ошибка считывания
                }
        }
        else{
                MSG("Готов, но не COM-порт\n");
                return (-1); // ошибка
        }
        MSG("считан сигнал: %d\n", rb);
        return (int)rb;
}

Поиграйтесь с параметрами select'а, тогда у вас не будет блокировок при ожидании очередной порции данных.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали: