Serial Programming HOWTO

Gary Frerking

        gary@frerking.org
      

Peter Baumann
Русский перевод А.Гавва (2002 г.Львов).

Revision History
Revision 1.01 2001-08-26 Revised by: glf
New maintainer, converted to DocBook
Revision 1.0 1998-01-22 Revised by: phb
Initial document release

Этот документ описывает как программировать связь с устройствами подключенными к последовательным портам компьютера под Linux.



1. Введение

Этот документ называется Linux Serial Programming HOWTO. Здесь описывается как программировать связь с другими устройствами/компьютерами через последовательную линию под Linux. Рассматриваются различная техника: Канонический ввод/вывод (прием/передача только полной строки), асинхронный ввод/вывод и ожидание ввода от различных источников.

Это - первое обновление начального релиза Linux Serial Programming HOWTO. Первичное назначение этого обновления - изменение авторской информации и конвертирование документа в формат DocBook. Относительно технического содержимого, на данный момент времени, изменений очень мало. Подчистка технического содержимого не может быть произведена за одну ночь, но я буду работать над этим когда мне позволит время.

Пожалуйста, шлите мне любые пожелания/замечания которые вы имеете, это будет очень ценно.

Все примеры тестировались при использовании i386 Linux Kernel 2.0.29.


1.1. Информация об авторских правах

This document is copyrighted (c) 1997 Peter Baumann, (c) 2001 Gary Frerking and is distributed under the terms of the Linux Documentation Project (LDP) license, stated below.

Unless otherwise stated, Linux HOWTO documents are copyrighted by their respective authors. Linux HOWTO documents may be reproduced and distributed in whole or in part, in any medium physical or electronic, as long as this copyright notice is retained on all copies. Commercial redistribution is allowed and encouraged; however, the author would like to be notified of any such distributions.

All translations, derivative works, or aggregate works incorporating any Linux HOWTO documents must be covered under this copyright notice. That is, you may not produce a derivative work from a HOWTO and impose additional restrictions on its distribution. Exceptions to these rules may be granted under certain conditions; please contact the Linux HOWTO coordinator at the address given below.

In short, we wish to promote dissemination of this information through as many channels as possible. However, we do wish to retain copyright on the HOWTO documents, and would like to be notified of any plans to redistribute the HOWTOs.

If you have any questions, please contact


1.2. Отказ от ответственности

Не принимаются никакие обязательства относительно содержимого этого документа. Приведенные в документе концепции, примеры и другое содержимое на свой страх и риск. Поскольку э то новая редакция этого документа, то в ней могут быть ошибки и опечатки, которые, естественно, могут повредить вашу систему. Относитесь к этому с осторожностью, и, хотя это не очень нравится, автор не принимает на себя никакой ответственности.

Все авторские права сохраняются за соответствующими владельцами, пока не будет указано обратное. Использование терминов в этом документе не дожно иметь отношение к нарушению любых торговых или сервисных марок.

Наименование определенных продуктов или брэндов не должно рассматриваться как индоссамент (передаточная надпись).

Вам строго рекомендуется выполнить резервное сохранение вашей системы перед основной инсталляцией и выполнять резервное сохранение вашей системы через определенные интервалы времени.


1.3. Новые версии

Как указывалось ранее, здесь мало изменений касающихся технического содержимого.


1.4. Благодарности

Автор благодарит Mr. Strudthoff, Michael Carter, Peter Waltenberg, Antonino Ianella, Greg Hankins, Dave Pfaltzgraff, Sean Lincolne, Michael Wiedmann, и Adrey Bonar.


1.5. Обратная связь

Ваши замечания и пожелания, касающиеся этого документа, естественно приветствуются. Без них этот документ не смог бы существовать. Пожалуйста, шлите ваши дополнения, комментарии и критику по следующему адресу : .


2. Getting started

2.1. Отладка

Лучший способ отладки вашего кода - это установка другой системы с Linux, и подключение двух компьютеров через нуль-модемный кабель. Используйте miniterm, который доступен из руководства программиста LDP( ftp://sunsite.unc.edu/pub/Linux/docs/LDP/programmers-guide/lpg-0.4.tar.gz в каталоге примеров ) для передачи символов на вашу систему Linux. Miniterm может быть легко скомпилирован и будет передавать необработанный клавиатурный ввод через последовательный порт. Должно быть проверено только предложение объявления #define MODEMDEVICE "/dev/ttyS0". Установите его в ttyS0 для COM1, ttyS1 для COM2, и т.д.. Это необходимо для проверки того, что все символы передаются в raw виде (без предварительной обработки) по последовательной линии. Для проверки вашего подключения, запустите miniterm на обоих компьютерах и просто попечатайте на клавиатуре. Символы введенные на клавиатуре одного компьютера должны появляться на экране другого компьютера и наоборот. Эхо ввода не будет появляться на локально подключенном экране.

Для создания нуль-модемного кабеля вам необходимо перекрутить линии TxD (передача) и RxD (прием). Описание кабеля см. в секции 7 Serial-HOWTO.

Выполнение такой проверки также возможно при использовании только одного компьютера, если вы имеете два неиспользуемых последовательных порта. Таким образом, вы можете запустить два miniterm на двух виртуальных консолях. Если вы освободили последовательный порт отключением мышки, то, если присутствует /dev/mouse, не забудьте его перенаправить. Если вы используете многопортовую последовательную плату, убедитесь в том, что вы ее правильно сконфигурировали. Я сам плохо сконфигурировал свою многопортовую последовательную плату и все было хорошо пока я работал на моем собственном компьютере, но когда я подключился к другому компьютеру, последовательный порт начал терять символы. Кроме того, запуск двух программ на одном компьютере не всегда может быть полностью асинхронным.


2.2. Установки порта

Устройства /dev/ttyS* предпологаются для подключения терминалов к вашей системе Linux и конфигурируются для этого во время запуска системы. Об этом необходимо помнить при программировании связи непосредственно через последовательные порты. Например, порты могут быть сконфигурированы во время запуска системы таким образом, что они возвращают "эхо" вводимого символа обратно, что обычно должно быть изменено при передаче данных.

Все параметры могут быть легко сконфигурированы из программы. Конфигурация сохраняется в структуре struct termios, которая объявлена в <asm/termbits.h>:

        #define NCCS 19
        struct termios {
                tcflag_t c_iflag;		/* флаги режима ввода (input) */
	        tcflag_t c_oflag;		/* флаги режима вывода (output) */
	        tcflag_t c_cflag;		/* флаги режима управления */
	        tcflag_t c_lflag;		/* флаги локального режима */
	        cc_t c_line;			/* дисциплина линии */
	        cc_t c_cc[NCCS];		/* управляющие символы */
        };
      

Этот файл также содержит все объявления флагов. Флаги режима ввода в c_iflag управляют всей обработкой ввода, которая подразумевает что символы посылаемые от устройства могут быть обработаны перед тем как они будут прочитаны вызовом read. Аналогично c_oflag управляет обработкой вывода. c_cflag содержит следующие установки для порта: скорость передачи данных, число битов в передаваемом символе, число стоп-битов, и т.д. Флаги локального режима храняться в c_lflag и определяют будет-ли производиться "эхо" для вводимых символов, какие сигналы будут посылаться программе, и т.д. В заключение, массив c_cc описывает управляющие символы для конца файла, остановки передачи, и т.д. Значения по умолчанию для управляющих символов описаны в <asm/termios.h>. Флаги описываются в странице руководства (man page) termios(3). Структура termios содержит c_line (дисциплина линии) элемент, который не используется в POSIX-совместимых системах.


2.3. Концепции ввода для последовательных устройств

Здесь будут представлены три различных концепции ввода. Для определенного приложения должна быть выбрана подходящая концепция. Если возможно, то не зацикливайте чтение одиночного символа для получения целой строки. Когда я так делал, я терял символы, в то время как read для целой строки не показывал ни одной ошибки.


2.3.1. Обработка канонического ввода

Это нормальный режим обработки для терминалов, но он также может быть полезен для коммуникации с другим dl вводом, обрабатываемым построчно, что подразумевает что read будет возвращать полнострочный ввод. Строка, по умолчанию, заканчивается NL (ASCII LF), символом конца строки или символом конца файла. Символ CR (по умолчанию, символ конца строки для DOS/Windows) не будет завершать строку при установках по умолчанию.

Обработка канонического ввода может также обрабатывать очистку, удаление слова, и перепечатку символов, транслировать CR в NL, и т.д.


2.3.2. Обработка неканонического ввода

Обработка неканонического ввода будет манипулировать фиксированным количеством символов в одной операции чтения, кроме того, это разрешает символьный таймер. Этот режим должен быть использован если ваше приложение всегда должно читать фиксированное количество символов, или если подключенное устройство посылает пакеты символов.


2.3.3. Асинхронный ввод

Два режима описанных выше могут быть использованы в синхронном и асинхронном режиме. Синхронный режим устанавливается по умолчанию, при этом вызов read будет заблокирован до тех пор пока операция чтения не будет завершена. В асинхронном режиме вызов read возвращает управление немедленно и посылает сигнал вызвавшей программе после завершения операции чтения. Этот сигнал может быть принят сигнальным обработчиком.


2.3.4. Ожидание ввода от множества источников

Эта ситуация не является отдельным режимом ввода, но может быть полезно если вы манипулируете несколькими устройствами. В моем приложении я управлял вводом через TCP/IP сокет и вводом через последовательное соединение с другим компьютером квази-последовательно. Пример программы показанный ниже будет ожидать ввод от двух источников ввода. Если ввод от одного из источников становится доступным, он будет обработан, и, затем, программа будет ожидать новый ввод данных.

Подход показанный ниже выглядит сложно, но необходимо не забывать о том, что Linux - это многозадачная операционная система. Системный вызов select не будет загружать процессор (CPU) при ожидании ввода, в то время как цикл ожидания пока ввод станет доступен будет замедлять одновременное выполнение других процессов.


3. Примеры программ

Все примеры программ порождены из miniterm.c. Размер приемного буфера ограничен 255 символами, подобно максимальной длине строки при обработке канонического ввода (<linux/limits.h> или <posix1_lim.h>).

Смотрите комментарии в коде которые объясняют использование различных режимов ввода. Я надеюсь что этот код понятен. Пример для канонического ввода откомментирован прекрасно, другие примеры откомментированы только там где они отличаются от примера для канонического ввода для того чтобы подчеркнуть различия.

Описания - не полны, но это поощряет вас поэкспериментировать с примерами для получения наилучшего решения для вашего приложения.

Don't forget to give the appropriate serial ports the right permissions Не забудьте предоставить правильные привелегии доступа к соответствующему последовательному порту (например: chmod a+rw /dev/ttyS1)!


3.1. Обработка канонического ввода

        #include <sys/types.h>
        #include <sys/stat.h>
        #include <fcntl.h>
        #include <termios.h>
        #include <stdio.h>

        /* установки скорости передачи данных объявлены в <asm/termbits.h>, 
        который включается в <termios.h> */
        #define BAUDRATE B38400

        /* измените эти объявления для корректного указания порта */
        #define MODEMDEVICE "/dev/ttyS1"
        #define _POSIX_SOURCE 1 /* POSIX-совместимый источник */

        #define FALSE 0
        #define TRUE 1

        volatile int STOP=FALSE; 

        main()
        {
          int fd,c, res;
          struct termios oldtio,newtio;
          char buf[255];
        /* 
          Открываем устройство модема для чтения и записи как неуправляющий
          терминал (tty), поскольку мы не хотим завершать процесс когда
          помехи в линии посылают сигнал CTRL-C.
        */
         fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY ); 
         if (fd <0) {perror(MODEMDEVICE); exit(-1); }
        
         tcgetattr(fd,&oldtio); /* save current serial port settings */
         bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */
        
        /* 
          BAUDRATE: устанавливает скорость передачи данных в bps.
                    Вы также могли бы использовать cfsetispeed и cfsetospeed.
          CRTSCTS : аппаратное управление выводным потоком данных (используется
                    только если кабель обладает всеми необходимыми сигнальными
                    линиями. См. секцию 7 Serial-HOWTO)
          CS8     : 8n1 (8 бит, без четности, 1 стоп-бит)
          CLOCAL  : локальное подключение, нет управления модемом
          CREAD   : разрешает прием символов
        */
         newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
         
        /*
          IGNPAR  : игнорировать байты с ошибками четности
          ICRNL   : отобразить символ CR на NL (иначе ввод CR на другом
                    компьютере не будет завершать ввод)
          иначе установить устройство как raw (нет обработки ввода)
        */
         newtio.c_iflag = IGNPAR | ICRNL;
         
        /*
         Raw вывод (нет обработки вывода).
        */
         newtio.c_oflag = 0;
         
        /*
          ICANON  : разрешить канонический ввод
          заблокировать любое функционирование "эхо", и не посылать сигналы
          к вызывающей программе
        */
         newtio.c_lflag = ICANON;
         
        /* 
          инициализация всех управляющих символов
          значения по умолчанию могут быть найдены в in /usr/include/termios.h,
          и даются в комментариях, но мы не нуждаемся в них здесь
        */
         newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */ 
         newtio.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
         newtio.c_cc[VERASE]   = 0;     /* del */
         newtio.c_cc[VKILL]    = 0;     /* @ */
         newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
         newtio.c_cc[VTIME]    = 0;     /* inter-character timer unused */
         newtio.c_cc[VMIN]     = 1;     /* blocking read until 1 character arrives */
         newtio.c_cc[VSWTC]    = 0;     /* '\0' */
         newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */ 
         newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
         newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
         newtio.c_cc[VEOL]     = 0;     /* '\0' */
         newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
         newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */
         newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
         newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
         newtio.c_cc[VEOL2]    = 0;     /* '\0' */
        
        /* 
          теперь очищаем модемную линию и активируем наши установки порта
        */
         tcflush(fd, TCIFLUSH);
         tcsetattr(fd,TCSANOW,&newtio);
        
        /*
          терминальные установки выполнены, теперь приступаем к обработке ввода
          В этом примере, ввод символа 'z' в начале строки будет завершать
          работу программы.
        */
         while (STOP==FALSE) {     /* цикл до тех пор пока не получим условие завершения */
         /* программа выполняет чтение блока до тех пор пока не будет получен
            символ завершения строки, даже если на ввод получено больше чем 255
            символов. Если число прочитанных символов меньше чем число доступных
            символов, то последующее чтение возвратит оставшиеся символы. 
            В переменной res будет установлено число реально прочитанных символов. */
            res = read(fd,buf,255); 
            buf[res]=0;             /* установить завершитель строки,
                                       таким образом, мы можем выполнять
                                       printf */
            printf(":%s:%d\n", buf, res);
            if (buf[0]=='z') STOP=TRUE;
         }
         /* восстановление старых установок порта */
         tcsetattr(fd,TCSANOW,&oldtio);
        }

      


3.2. Обработка неканонического ввода

В режиме обработки неканонического ввода, не производится построчная сборка ввода и обработка ввода (очистка, удаление слов, и т.д.) не производится. Два параметра управляют поведением этого режима: c_cc[VTIME] устанавливает символьный таймер, и c_cc[VMIN] устанавливает минимальное количество символов которые необходимо принять для удовлетворения операции чтения.

Если MIN > 0 и TIME = 0, то MIN устанавливает количество символов которые необходимо принять для удовлетворения операции чтения. Так как TIME установлено в нуль, то таймер не используется.

Если MIN = 0 и TIME > 0, то TIME служит как значение таймаута. Операция чтения будет удовлетворена если будет прочитан одиночный символ, или TIME будет превышен (t = TIME *0.1 s). Если TIME превышено, то не будет возвращено ни одного символа.

Если MIN > 0 и TIME > 0, то TIME служит как межсимвольный таймер. Операция чтения будет удовлетворена если будет принято MIN символов, или время между передачей двух символов достигло TIME. Таймер рестартует каждый раз при приеме нового символа и активируется после приема первого символа.

Если MIN = 0 и TIME = 0, то чтение будет удовлетворено немедленно. При этом операция чтения вернет число фактически доступных символов или число запрошенных символов. Согласно Antonino (см. содействие), вы можете выдать fcntl(fd, F_SETFL, FNDELAY); перед чтением для получения таких же результатов.

При модификации newtio.c_cc[VTIME] и newtio.c_cc[VMIN] могут быть проверены все режимы описанные выше.

      #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>
      #include <termios.h>
      #include <stdio.h>
        
      #define BAUDRATE B38400
      #define MODEMDEVICE "/dev/ttyS1"
      #define _POSIX_SOURCE 1 /* POSIX-совместимый источник */
      #define FALSE 0
      #define TRUE 1
        
      volatile int STOP=FALSE; 
       
      main()
      {
        int fd,c, res;
        struct termios oldtio,newtio;
        char buf[255];
        
        fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY ); 
        if (fd <0) {perror(MODEMDEVICE); exit(-1); }
        
        tcgetattr(fd,&oldtio); /* сохранение текущих установок порта */
        
        bzero(&newtio, sizeof(newtio));
        newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
        newtio.c_iflag = IGNPAR;
        newtio.c_oflag = 0;
        
        /* set input mode (non-canonical, no echo,...) */
        newtio.c_lflag = 0;
         
        newtio.c_cc[VTIME]    = 0;   /* посимвольный таймер не используется */
        newtio.c_cc[VMIN]     = 5;   /* блокировка чтения до тех пор пока
                                        не будут приняты 5 символов */
        
        tcflush(fd, TCIFLUSH);
        tcsetattr(fd,TCSANOW,&newtio);
        
        
        while (STOP==FALSE) {       /* цикл ввода */
          res = read(fd,buf,255);   /* выход после приема/ввода 5-ти символов */
          buf[res]=0;               /* для того чтобы мы могли использовать printf... */
          printf(":%s:%d\n", buf, res);
          if (buf[0]=='z') STOP=TRUE;
        }
        tcsetattr(fd,TCSANOW,&oldtio);
      }
    


3.3. Асинхронный ввод

      #include <termios.h>
      #include <stdio.h>
      #include <unistd.h>
      #include <fcntl.h>
      #include <sys/signal.h>
      #include <sys/types.h>
        
      #define BAUDRATE B38400
      #define MODEMDEVICE "/dev/ttyS1"
      #define _POSIX_SOURCE 1 /* POSIX-совместимый источник */
      #define FALSE 0
      #define TRUE 1
        
      volatile int STOP=FALSE; 
        
      void signal_handler_IO (int status);   /* объявление обработчика сигнала */
      int wait_flag=TRUE;                    /* TRUE пока не получен сигнал */
        
      main()
      {
        int fd,c, res;
        struct termios oldtio,newtio;
        struct sigaction saio;           /* объявление действия сигнала (signal action) */
        char buf[255];
        
        /*
          открываем устройство как не блокируемое (вызов read будет возвращать управление немедленно)
        */
        fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
        if (fd <0) {perror(MODEMDEVICE); exit(-1); }
        
        /*
          устанавливаем обработчик сигнала перед установкой устройства как асинхронного
        */
        saio.sa_handler = signal_handler_IO;
        saio.sa_mask = 0;
        saio.sa_flags = 0;
        saio.sa_restorer = NULL;
        sigaction(SIGIO,&saio,NULL);
          
        /*
          разрешаем процессу получать SIGIO
        */
        fcntl(fd, F_SETOWN, getpid());

        /*
          делаем файловый дескриптор асинхронным (страница руководства
          говорит, что только O_APPEND и O_NONBLOCK будут работать
          с F_SETFL...)
        */
        fcntl(fd, F_SETFL, FASYNC);
        
        tcgetattr(fd,&oldtio); /* save current port settings */

        /*
          устанавливаем новые установки порта для обработки канонического ввода
        */
        newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
        newtio.c_iflag = IGNPAR | ICRNL;
        newtio.c_oflag = 0;
        newtio.c_lflag = ICANON;
        newtio.c_cc[VMIN]=1;
        newtio.c_cc[VTIME]=0;
        tcflush(fd, TCIFLUSH);
        tcsetattr(fd,TCSANOW,&newtio);
         
        /*
          цикл ожидания ввода. обычно, мы будем делать здесь что-нибудь полезное
        */
        while (STOP==FALSE) {
          printf(".\n");usleep(100000);
          /*
            после получения SIGIO, wait_flag = FALSE, ввод доступен
            и может быть прочитан
          */
          if (wait_flag==FALSE) { 
            res = read(fd,buf,255);
            buf[res]=0;
            printf(":%s:%d\n", buf, res);
            if (res==1) STOP=TRUE; /* останавливаем цикл при вводе символа CR */
            wait_flag = TRUE;      /* ждем нового воода */
          }
        }
        /*
          восстанавливаем старые установки порта
        */
        tcsetattr(fd,TCSANOW,&oldtio);
      }
        
      /***************************************************************************
      * обработчик сигнала. устанавливает wait_flag в FALSE для индикации        *
      * вышеприведенному циклу, что есть принятый символ                         *
      ***************************************************************************/
        
      void signal_handler_IO (int status)
      {
        printf("received SIGIO signal.\n");
        wait_flag = FALSE;
      }
    


3.4. Ожидание ввода от множества источников

Эта секция оставлена минимальной. Она предназначена быть только подсказкой, и, таким образом, код примера очень краток. Это будет работать не только с последовательными портами, но и с любым множеством файловых дескрипторов.

Вызов select и сопутствующие макросы используют fd_set. Это битовый массив, который имеет определенный бит для каждого правильного/существующего номера файлового дескриптора. select будет принимать fd_set с установленными битами для соответствующих файловых дескрипторов и возвращать fd_set, в котором биты, соответствующие файловым дескрипторам, установлены когда произошел ввод, вывод, или исключение. Вся обработка fd_set выполняется с помощью предусмотренных макросов. Обратитесь к странице руководства (man page) select(2).

      #include <sys/time.h>
      #include <sys/types.h>
      #include <unistd.h>
        
      main()
      {
        int    fd1, fd2;  /* источники ввода 1 и 2 */
        fd_set readfs;    /* множество файловых дескрипторов */
        int    maxfd;     /* максимальный используемый номер
                             для файлового дескриптора
                             (maximum file desciptor used) */
        int    loop=1;    /* цикл пока TRUE */ 
        
        /*
          open_input_source открывает устройство, корректно устанавливает порт,
          и возвращает номер файлового дескриптора
        */
        fd1 = open_input_source("/dev/ttyS1");   /* COM2 */
        if (fd1<0) exit(0);
        fd2 = open_input_source("/dev/ttyS2");   /* COM3 */
        if (fd2<0) exit(0);
        maxfd = MAX (fd1, fd2)+1;  /* максимальная битовая позиция (fd) для проверки */
        
        /*
          цикл ввода
        */
        while (loop) {
          FD_SET(fd1, &readfs);  /* установить проверку для источника 1 */
          FD_SET(fd2, &readfs);  /* установить проверку для источника 2 */

          /*
            блокировка до тех пор пока ввод не станет доступен
          */
          select(maxfd, &readfs, NULL, NULL, NULL);
          if (FD_ISSET(fd1))         /* ввод от источника 1 доступен */
            handle_input_from_source1();
          if (FD_ISSET(fd2))         /* ввод от источника 2 доступен */
            handle_input_from_source2();
        }
      }   
    

Данный пример производит блокировку на неопределенное время, до тех пор, пока данные от одного из источников ввода не будут доступны. Если вам необходим таймаут ввода, то измените вызов select как указано ниже:

        int res;
        struct timeval Timeout;

        /*
          установка значения таймаута внутри цикла ввода
        */
        Timeout.tv_usec = 0;  /* миллисекунды */
        Timeout.tv_sec  = 1;  /* секунды */
        res = select(maxfd, &readfs, NULL, NULL, &Timeout);
        if (res==0)
        /*
          число файловых дескрипторов ввода = 0, произошел таймаут
        */ 
      

Этот пример будет "вываливаться" в таймаут через 1 секунду. Если произошел таймаут, то вызов select будет возвращать 0, однако позаботьтесь чтобы Timeout определялся временем актуального ожидания ввода в select. Если значение таймаута - нуль, то вызов select будет возвращать управление немедленно.


4. Другие источники информации

  • Linux Serial-HOWTO описывает как установить и сконфигурировать последовательные порты, а также содержит дополнительную информацию об оборудовании.

  • "Serial Programming Guide for POSIX Compliant Operating Systems", автор Michael Sweet.

  • Справочная страница руководства (man page) termios(3) описывает все флаги для структуры termios.



Наш баннер
Вы можете установить наш баннер на своем сайте или блоге, скопировав этот код:
RSS новости