2013-05-14 2 views
0

Я новичок в программировании Linux. Я следовал примеру в Интернете для чтения/записи в консоль, например, «/ dev/ttyS0». Каждый раз, когда я запускаю код, он выходит, не запрашивая пользователя для ввода ввода. Он также искажает терминальную строку (перевод строки) и я не могу видеть, что я печатаю ... Вот код, я использую:запрос терминала искажен и не читается

int main(int argc, char** argv) 
{ 
    struct termios tio; 
    struct termios stdio; 
    int tty_fd; 
    /* fd_set rdset; */ 

    printf("Please start with %s /dev/ttyS0 (for example)\n",argv[0]); 
    unsigned char mesg='D'; 

    memset(&stdio,0,sizeof(stdio)); 
    stdio.c_iflag=0; 
    stdio.c_oflag=0; 
    stdio.c_cflag=0; 
    stdio.c_lflag=0; 
    stdio.c_cc[VMIN]=1; 
    stdio.c_cc[VTIME]=0; 
    tcsetattr(STDOUT_FILENO,TCSANOW,&stdio); 
    tcsetattr(STDOUT_FILENO,TCSAFLUSH,&stdio); 
    fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);  // make the reads non-blocking 

    memset(&tio,0,sizeof(tio)); 
    tio.c_iflag=0; 
    tio.c_oflag=0; 
    tio.c_cflag=CS8|CREAD|CLOCAL;   // 8n1, see termios.h for more information 
    tio.c_lflag=0; 
    tio.c_cc[VMIN]=1; 
    tio.c_cc[VTIME]=5; 

    tty_fd=open(argv[1], O_RDWR | O_NONBLOCK | O_NOCTTY); 
    cfsetospeed(&tio,B115200);   // 115200 baud 
    cfsetispeed(&tio,B115200);   // 115200 baud 

    tcsetattr(tty_fd,TCSANOW,&tio); 
    while (mesg != 'q') { 
    if (read(tty_fd,&mesg,1)>0)  write(STDOUT_FILENO,&mesg,1);    // if new data is available on the serial port, print it out 
    if (read(STDIN_FILENO,&mesg,1)>0) write(tty_fd,&mesg,1);      // if new data is available on the console, send it to the serial port 
    } 

    close(tty_fd); 

    return(0); 
} 
+0

* «Я следовал примеру в Интернете ...» * - Тогда вы можете использовать плохой пример. Вызов 'memset (, 0,)', а затем присвоение 0 элементам структуры является избыточным и может вызвать проблемы. Правильная практика для POSIX - это вызов 'tcgetattr()', а затем изменение отдельных атрибутов. См. [Руководство по серийному программированию для операционных систем POSIX] (http://www.cmrr.umn.edu/~strupp/serial.html). Обнуление атрибутов для 'stdout', безусловно, неверно и вызовет проблемы – sawdust

ответ

1

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

Это можно сделать так:

$ SAVED_TTY=$(stty -g)   # save the good settings once 
$ ./a.out ; stty $SAVED_TTY  # restore than after each run of the program 

-g вариант stty приводит к его выходу всех настроек TTY «соленых» в строку символов, которая является приемлемой в качестве аргумента будущего вызова stty, чтобы восстановить те же настройки.

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

Что касается вопроса о том, как обратимся к тому, что написано на устройстве tty, в этой подсистеме tty нет общей функциональности. Стандартный модуль дисциплины tty line может повторять входящие символы на выходе, так что, когда пользователи используют линейно-ориентированные программы, они могут видеть свою собственную типизацию, но нет петлевой программы, в которой устройство tty претендует на получение некоторых символов, которые оно имеет просто отправлено.

Однако некоторые последовательные аппаратные средства способны к аппаратным замыканиям: по существу, связывая линию UART TX с линией RX для целей тестирования.

Linux tty поддерживает модемное управление ioctl, которое можно использовать для включения и выключения, если аппаратное обеспечение поддерживает его. Это принимает форму TIOCMGET и TIOCMSET ioctls. Эти ioctls работают со значением, которое является логическим ИЛИ различных масок, одним из которых является TIOCM_LOOP.

Итак, я считаю, что создание аппаратной проверки по шлейфу идет что-то вроде этого:

unsigned int modem_control_bits; 

result = ioctl(tty_descriptor, TIOCMGET, &modem_control_bits); 
/* check result for error, of course */ 

modem_control_bits |= TIOCM_LOOP; /* request loopback from serial port */ 

result = ioctl(tty_descriptor, TIOCMSET, &modem_control_bits); 
/* check result for error */ 

Это не ясно, будет ли каждый последовательный драйвер сообщает об ошибке, если оно будет предложено установить TIOCM_LOOP, но оборудование не поддерживает Это. (Я не думаю, что только потому, что результат равен нулю, он обязательно работал).

Есть и другие TIOCM_* биты, поэтому вы можете делать стандартные вещи, такие как включение и выключение DTR, или определить, включен ли индикатор звонка и еще много чего.

+0

Да, это помогает. – iamauser

+0

Вы должны поместить некоторый небольшой второстепенный сон в цикл, иначе он будет вращаться на 100% CPU через неблокирующие чтения. – Kaz

+0

Вы говорите о цикле 'while' в коде? Кстати, как мне прочитать символы, которые я только что написал на терминале «/ dev/ttyS0». – iamauser

Смежные вопросы