У меня есть устройство, которое отправляет информацию через USB на мой компьютер. Arch Linux настраивает это устройство, создавая файл с именем ttyUSB0
в /dev/
. Я использовал GTKterm
для получения этой входящей информации и отображения ее в эмулируемом окне терминала.
Мой вопрос в том, как именно происходит GTKterm
чтение/запись в этот ttyUSB0
файл, и где я могу начать изучать, как реализовать подобную функциональность? То есть, в самой простой форме, как я могу записать символ в ttyUSB0
, или, напротив, получить байт и записать его в файл?
решение1
TTY — это файлы, которые вы можете использовать так же, как и любые другие. Вы можете открывать их стандартными инструментами открытия файлов вашего языка и читать или писать из них. У них есть особое поведение, которое отличается от «обычных» файлов, но основы те же. Я расскажу о некоторых особых случаях в конце, но сначала эксперимент.
Одна интересная вещь, которую вы можете сделать прямо из обычного терминала. Запустите tty
и он выведет строку типа:
/dev/pts/2
Это устройство TTY, на котором работает ваш терминал. Вы можете что-нибудь написать на этом терминале:
$ echo Hello > /dev/pts/2
Hello
$
Вы даже можете прочитать оттуда:
$ read X < /dev/pts/2
hello
$ echo $X
hello
$
( read X
— это команда sh «считывать строку из стандартного ввода в переменную X»; < — использовать /dev/pts/2 в качестве стандартного ввода для команды чтения; первое «hello» я набрал, а второе было распечатано).
Если вы откроете другую оболочку, скажем, с помощью screen
или xterm
, вы можете запустить run echo spooky > /dev/pts/2
в этой оболочке, чтобы текст появился на вашем исходном терминале, и то же самое для других команд. Все это просто ваша оболочка открывает файл, не зная, что это TTY.
Вот очень простая программа на языке C, которая делает именно то, что вы просили: записывает один символ в /dev/pts/3, а затем считывает из него один байт:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
char byte;
int fd = open("/dev/pts/3", O_RDWR);
write(fd, "X", 1);
ssize_t size = read(fd, &byte, 1);
printf("Read byte %c\n", byte);
return 0;
}
Настоящее устройство TTY, подключенное к оболочке или эмулятору терминала, будет вести себя интересно, но вы должны что-то получить взамен.
Чтобы получить доступ к терминалу, вам необходимо разрешение на его использование. Это просто стандартные разрешения для файлов, которые вы видите ls -l
и устанавливаете с помощью chmod
: вам необходимо разрешение на чтение, чтобы открыть файл и прочитать его, и разрешение на запись, чтобы записать в него. TTY, которые поддерживают ваш терминал, будут принадлежать вам, но TTY другого пользователя не будут, а TTY для USB-устройств могут принадлежать вам или нет, в зависимости от вашей конфигурации. Вы можете изменить разрешения так же, как и всегда.
Что касается написания программы для работы с ним, вам не нужно делать ничего особенного. Вы можете видеть в примере, что одна вещь, которую выненужно сделать, это закрыть файл каждый раз, чтобы ваши данные были прочитаны на другом конце: файлы TTY действуют как конвейеры, просто передавая данные в обоих направлениях по мере их поступления. Когда я писал текст в TTY, он появлялся немедленно, а когда я читал его впоследствии, меня уже ничего не ждало. Этонеткак запись в обычный файл, когда данные сохраняются на диске — они немедленно передаются на другую сторону или хранятся в памяти до тех пор, пока кто-то их не прочитает.
Вы можете использоватьвыбиратьфункция, позволяющая вам заниматься другими делами, пока вы ждете, пока устройство что-то скажет, но если вы готовы просто ждать поступления данных, вы можете просто использовать блокировку чтения и позволить ОС сделать всю работу.
Следует помнить, что в ядре может быть ограничен размер буфера, и если вы пишете много данных за раз, вы можете неожиданно заблокироваться. Если это может стать проблемой, используйтенеблокирующий ввод-выводс open("/dev/...", O_RDWR | O_NONBLOCK)
. Принцип в любом случае будет один и тот же.