LINUX.ORG.RU

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


0

2

Здравствуйте уважаемые. Я хочу попросить вас помочь мне в оптимизации моей программки для чтения данных с ком порта. На данный момент меня не устраивает сам алгоритм который я использую в программе для чтения, так как он использует циклы которые грузят процессор до 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); // функция обработки данных собранных в массив
    
     }
    
  }
  

  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;
}


А что мешает читать сразу все 16 байт одним вызовом read?

grouzen ★★
()
Ответ на: комментарий от TITO

У меня работа с последовательным портом выглядит так.

#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <time.h>

unsigned char buf[4096];

int openport(const char *file) {
    int fd = open(file, O_RDWR|O_NOCTTY);
    return fd;
}

#define B(a) \
  case a: \
    baud = B##a; \
    break;

int config_port(int fd, int rate) {
    struct termios term_p;
    tcgetattr(fd, &term_p);

    int baud = 0;
    switch (rate) {
        B(50)
        B(75)
        B(110)
        B(57600)
        B(115200)
        B(230400)
        B(460800)
        B(500000)
        B(576000)
        B(921600)
        B(1000000)
        B(1152000)
        B(1500000)
        B(2000000)
        B(2500000)
        B(3000000)
        B(3500000)
        B(4000000)
      default:
        printf("config_port: invalid rate value %d\n", rate);
        return 0;
    }

    memset(&term_p, 0, sizeof(term_p));

    term_p.c_cflag = baud | CS8 | CLOCAL | CREAD;
    term_p.c_iflag = IGNPAR;
    term_p.c_oflag = IGNPAR;
    term_p.c_lflag = 0;

    term_p.c_cc[VTIME] = 0;
    term_p.c_cc[VMIN] = 0;

    tcflush(fd, TCIFLUSH);

    if (cfsetispeed(&term_p, baud) == -1) {
        perror("cfsetispeed");
        return 0;
    }
    if (cfsetospeed(&term_p, baud) == -1) {
        perror("cfsetospeed");
        return 0;
    }
    tcflush(fd, TCIFLUSH);
    if (tcsetattr(fd, TCSANOW, &term_p) == -1) {
        perror("tcsetattr");
        return 0;
    }
    return 1;
}

int waitread(int fd) {
    fd_set rfds;
    struct timeval tv;
    int retval;

    FD_ZERO(&rfds);
    FD_SET(fd, &rfds);

    tv.tv_sec = 0;
    tv.tv_usec = 200000;
    retval = select(fd+1, &rfds, NULL, NULL, &tv);

    if (retval == -1) {
        perror("select");
        return 0;
    } else return 1;
}
А потом read(fd, , ) / write(fd, , )

unnamed
()
Ответ на: комментарий от unnamed

Небольшой комментарий: извращение с 115200 -> B115200 в switch(rate), конечно, во многих случаях будет лишним, но у меня rate вводится пользователем.

unnamed
()
Ответ на: комментарий от grouzen

Если данных нет, то read не отдаст управление.

Поэтому я для таких дел использую либо poll, или если совсем лениво, то libevent

Dark_SavanT ★★★★★
()
Ответ на: комментарий от Dark_SavanT

Как раз таки отдает, open делается с O_NDELAY.

и да select/poll/... спасет + чтение более чем 1 байт за раз.

что то типа:

char buffer[12]; size_t offset = 0;

while (!stop) { /* write your select/poll/... here */

ssize_t count = read(fd, buffer + offset, sizeof(buffer) - offset); if (...) /* check errors here */ { } offset += count; if (offset == sizeof(buffer)) { crtfile(...) offset = 0; } }

indie
()
Ответ на: комментарий от unnamed

код близнец

#define STATE(e) \
    case e: \
	    out += #e; \
	    break

#define QTATE(e) \
    case e: \
	    out += &5[#e]; \
	    break

static
CAtlString
ThreadState(DWORD ProcessId, DWORD ThreadId)
{
	CAtlString out;
	ULONG Result = ThreadStateWaitReason(ProcessId, ThreadId);
	switch (LOWORD(Result))
	{
		QTATE(StateInitialized);
		QTATE(StateReady);
		QTATE(StateRunning);
		QTATE(StateStandby);
		QTATE(StateTerminated);
		QTATE(StateWait);
		QTATE(StateTransition);
		QTATE(StateUnknown);
	}

	if (LOWORD(Result) != StateWait)
		return out;
	
	out += ":";
	
	switch (HIWORD(Result))
	{
		STATE(Executive);
		STATE(FreePage);
		STATE(PageIn);
		STATE(PoolAllocation);
		STATE(DelayExecution);
		STATE(Suspended);
		STATE(UserRequest);
		STATE(WrExecutive);
		STATE(WrFreePage);
		STATE(WrPageIn);
		STATE(WrPoolAllocation);
		STATE(WrDelayExecution);
		STATE(WrSuspended);
		STATE(WrUserRequest);
		STATE(WrEventPair);
		STATE(WrQueue);
		STATE(WrLpcReceive);
		STATE(WrLpcReply);
		STATE(WrVirtualMemory);
		STATE(WrPageOut);
		STATE(WrRendezvous);
		STATE(Spare2);
		STATE(Spare3);
		STATE(Spare4);
		STATE(Spare5);
		STATE(Spare6);
		STATE(WrKernel);
		STATE(MaximumWaitReason);
	}

	return out;
}
anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.