Como ler / gravar no dispositivo tty *?

29

Eu tenho um dispositivo que envia informações via USB para o meu computador. Arch Linux configura este dispositivo através da criação de um arquivo chamado ttyUSB0no /dev/. Eu tenho usado GTKtermpara receber essas informações e exibi-las em uma janela de terminal emulada.

Minha pergunta é: como exatamente GTKtermlê / grava neste ttyUSB0arquivo e onde posso começar a aprender a implementar funcionalidades semelhantes? Ou seja, da forma mais básica, como posso escrever um caractere ttyUSB0ou, em contraste, receber um byte e gravá-lo em um arquivo?

sherrellbc
fonte
1
Tente usar o gato para ler e eco para escrever. "Tudo é um arquivo" em unix :)
dchirikov
Você pode tentar abrir um console serial nele. screenpode fazer isso eminiterm
mikeserv
Eu estava pensando em termos de uma abordagem programática. Se isso for verdade e realmente fácil (sendo apenas abrir e ler o arquivo), você escreveria um loop infinito para abrir, ler, fechar o arquivo e atualizar continuamente quando novos dados estiverem presentes desde a época anterior? O que acontece se o dispositivo 'tty' tentar gravar no arquivo se você o abrir no seu programa?
sherrellbc
Pode ser que ajude: cmrr.umn.edu/~strupp/serial.html : abra (), leia (), escreva () e selecione (). Nada de especial, ao que parece.
dchirikov
@sherrellbc - você pode criar scripts screene / ou minitermprogramaticamente.
mikeserv

Respostas:

38

TTYs são arquivos que você pode usar como qualquer outro. Você pode abri-los com as ferramentas padrão de abertura de arquivos do seu idioma e ler ou escrever a partir deles. Eles têm um comportamento especial diferente dos arquivos "comuns", mas o básico é o mesmo. Vou cobrir alguns dos casos especiais no final, mas primeiro, um experimento.

Uma coisa interessante que você pode fazer diretamente de um terminal regular. Execute ttye ele imprimirá uma linha como:

/dev/pts/2

Esse é o dispositivo TTY em que seu terminal está sendo executado. Você pode escrever algo nesse terminal:

$ echo Hello > /dev/pts/2
Hello
$

Você pode até ler:

$ read X < /dev/pts/2
hello
$ echo $X
hello
$

(o read Xcomando sh é "ler uma linha da entrada padrão para a variável X"; <é usar / dev / pts / 2 como entrada padrão para o comando read; o primeiro "olá" que eu digitei e o segundo foi impresso) .

Se você abrir outro shell, digamos, usando screenou xterm, poderá executar run echo spooky > /dev/pts/2nesse shell para fazer com que o texto apareça no seu terminal original e o mesmo para os outros comandos. Tudo isso é apenas o shell que abre um arquivo sem saber que é um TTY.


Aqui está um programa C muito simples que faz exatamente o que você pediu e grava um único caractere em / dev / pts / 3, e depois lê um único byte:

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

Um dispositivo TTY real conectado a um emulador de terminal ou shell terá um comportamento interessante, mas você deve receber algo em troca.


Para acessar um terminal, você precisa ter permissão para usá-lo. Essas são apenas as permissões de arquivo padrão que você vê ls -le define chmod: você precisa de permissão de leitura para abrir o arquivo e lê-lo, e permissão de gravação para escrever nele. Os TTYs que suportam seu terminal pertencem a você, mas o TTY de outro usuário não, e os TTYs para dispositivos USB podem ou não ser, dependendo da sua configuração. Você pode alterar as permissões da mesma maneira como sempre.

Quanto a escrever um programa para trabalhar com ele, você não precisa fazer muita coisa especial. Você pode ver no exemplo que uma coisa que você não precisa fazer é fechar o arquivo toda vez para que seus dados sejam lidos pela outra extremidade: os arquivos TTY agem como pipelines, apenas empurrando os dados nas duas direções à medida que entram. Quando escrevi um texto para o TTY, ele apareceu imediatamente, e quando o li depois não havia mais nada esperando por mim. É não como escrever para um arquivo regular, onde os dados são salvos no disco - que é transmitido imediatamente para o outro lado, ou armazenados na memória até que alguém lê-lo.

Você pode usar a função de seleção para poder fazer outras coisas enquanto espera o dispositivo dizer alguma coisa, mas se estiver feliz em esperar a chegada dos dados, basta usar o bloqueio de leituras e deixar o sistema operacional funcionar. o levantamento.

Uma coisa a ter em mente é que existe um tamanho de buffer limitado no kernel, e se você escrever muitos dados de uma só vez, poderá acabar bloqueando sem querer. Se isso for um problema, use E / S sem bloqueioopen("/dev/...", O_RDWR | O_NONBLOCK) . O princípio será o mesmo de qualquer maneira.

Michael Homer
fonte
Estou tentando sudo echo Hello > /dev/tty4quando estou no ambiente de área de trabalho, mas recebo bash: /dev/tty4: Permission deniedse não estiver conectado ao tty4. No entanto, se eu estiver logado no tty4, tudo funcionará bem. Qual é a razão para isto?
Utku 15/05
@ Utku, isso certamente é algum tipo de problema de permissão que é removido após a autenticação no terminal virtual. Verifique as permissões de arquivo antes e depois de ter logado.ls -l /dev/tty4
sherrellbc
1
a > /dev/tty4parte não faz parte do echosubprocesso iniciado, sudomas parte do sudopróprio processo, que é executado pelo usuário atual. as permissões de arquivo para o usuário atual se aplicam em vez da raiz.
Robin479