будут рассматриваться позже. Они используются как часть обработки входных данных в цикле ввода-вывода в конце функции
main
.
Условно скомпилированный
sleep(600)
в начале функции
main
предназначен для отладки. С целью отладки программ, модифицирующих настройки
termios
для стандартных входных или выходных данных, лучше всего присоединить процесс в другой окне или терминальном сеансе. Однако это означает, что нельзя установить точку прерывания на основную функцию и проходить по одной инструкции за раз. Необходимо запустить
программу, найти идентификатор ее процесса и присоединиться к ней из отладчика. Более подробно этот процесс описан далее в настоящей главе.
Поэтому если необходимо отладить код, запускаемый до того, как программа дождется входных данных, нужно перевести программу в режим ожидания, чтобы оставить время для присоединения. После прикрепления режим ожидания прерывается, поэтому длительный режим ожидания безопасен. Чтобы активизировать это свойство, скомпилируйте
robin.с
с опцией
– DDSLEEP
.
Игнорируя отладку, мы в первую очередь анализируем опции, используя библиотеку
popt
, описанную в главе 26, а затем открываем последовательный порт, с которым будем взаимодействовать.
Затем мы вызываем функцию
tcgetattr
, чтобы получить существующую конфигурацию
termios
последовательного порта, а затем сохраняем копию в
pots
, чтобы восстановить ее по окончании.
Начиная со строки 183, мы модифицируем установки последовательного порта:
183: pts.c_lflag &= ~ICANON;
Эта строка отключает приведение к каноническому виду в драйвере последовательного порта — то есть переводит его в неформатируемый режим. В этом режиме нет специальных символов — ни символов новой строки, ни управляющих символов:
184: pts.c_lflag &= ~(ECHO | ECHOCTL | ECHONL);
Это отключает локальный эхо-контроль в последовательном порте:
185: pts.c_cflag |= HUPCL;
Если подключен модем,
HUPCL
сообщает ему об отбое при закрытии устройства конечной программой:
186: pts.с_сс[VMIN] = 1;
187: pts.с_сс[VTIME] = 0;
Когда tty находится в неформатируемом режиме, эти две установки определяют поведение системного вызова
read
. Эта особая установка сообщает, что при вызове
read
мы хотим, чтобы он подождал с возвратом, пока не считаются один или несколько байтов. Мы никогда не вызовем
read
, пока не будем знать, что остался хотя бы один байт для чтения, потому это функциональный эквивалент неблокирующего
read
. Определение
VMIN
и
VTIME
сложное, как показано далее в настоящей главе.
Настройки
termios
по умолчанию включают преобразование некоторых символов в конце строки. Это подходит для модемных линий и терминальных сеансов, но при соединении двух tty повтор преобразования нежелателен. Нежелательно отображать символы новой строки на пару "возврат каретки/перевод строки" при выводе, а также принимаемый возврат каретки — на перевод строки при вводе, поскольку мы уже получаем пары "возврат каретки/перевод строки" с удаленной системы.
194: pts.c_oflag &= ~ONLCR;
195: pts.c_iflag &= ~ICRNL;
Без этих двух строк использование программы
robin
для соединения с другим компьютером Linux или Unix приведет к тому, что удаленная система увидит, что вы нажимаете клавишу <Enter> дважды всякий раз, когда вы нажимаете ее один раз. И всякий раз, когда она будет
пытаться отобразить новую строку на вашем экране, вы будете видеть две строки. Поэтому каждый раз при нажатии <Enter> (предполагая, что у вас получится зарегистрироваться в этих установках терминала) вы увидите отраженные подсказки. Если же вы запустите
vi
, то увидите символы
~
, расположенные через строку, а не в каждой строке.
Таким образом, мы внесли в настройки
termios
все изменения, которые необходимо сделать перед обработкой аргументов командной строки. Теперь приступим к модификации настроек tty, предоставляющего стандартные входные и выходные данные. Поскольку это один tty, необходимо обработать лишь один файловый дескриптор из пары. Мы отдали предпочтение стандартному вводу, выбрав соглашение, установленное программой stty. И снова все начинается с получения и сохранения атрибутов.
Затем потребуется модифицировать несколько флагов:
201: sts.c_iflag &= ~(BRKINT | ICRNL);
202: sts.c_iflag |= IGNBRK;
203: sts.c_lflag &= ~ISIG;
Отключение
BRKINT
играет роль только в том случае, если robin вызывается из регистрационного сеанса, присоединенного к другому последовательному порту, на котором можно получить разрыв. Его отключение означает, что драйвер tty не посылает
SIGINT
в
robin
, когда в стандартном устройстве ввода
robin
возникает разрыв, поскольку
robin
не может сделать ничего полезного при получении разрыва. Отключение
ICRNL
предотвращает сообщение в
robin
о любых символах возврата каретки (
'\r'
) как о символах новой строки (
'\n'
). Как и при отключении
BRKINT
это действует лишь тогда, когда сеанс регистрации присоединяется к другому последовательному порту. Также это действует тогда, когда символы возврата каретки не игнорируются (то есть если не установлен флаг
Это флаги обработки входных данных. Также модифицируется локальный флаг обработки: отключается
ISIG
. Это предотвращает драйвер tty от передачи
SIGINT
,
SIGQUIT
и
SIGTSTP
при получении соответствующего символа (
INTR
,
QUIT
или
SUSP
). Мы делаем это потому, что хотим переслать эти символы на удаленную систему (или на другое устройство, подключенное к последовательному порту) для последующей обработки там.
Затем следует обработка опций. В некоторых случаях модификаций настроек
termios
по умолчанию может оказаться недостаточно, или же, наоборот, слишком много. В таких случаях мы предлагаем некоторые опции командной строки для модификации опций
termios
.
По умолчанию мы оставляем последовательный порт в том состоянии управления потоком, в котором мы его находим. Однако в строке 212 есть опции аппаратного управления потоком (использующего управляющие провода CTS и RTS), программного управления потоком (резервирование ^S и ^Q для STOP и START соответственно) и полного отключения управления потоком.