[Cascavel-pm] Porta serial (Was: Re: Porta paralela)

Daniel Ruoso daniel em ruoso.com
Quarta Junho 17 13:42:47 PDT 2009


Em Qua, 2009-06-17 às 15:43 -0300, João Gabriel Casteluber Laass
escreveu:
> Existe a possibilidade de usar um script Perl (em ambiente Linux) para
> enviar e receber dados para a porta paralela (/dev/ttyS0)? Alguém já
> fez isso com Perl? Devo me aventurar em Perl ou correr pro C?

Bom, você acabou de listar o caso mais evidente de quando programar para
Linux é infinitamente mais fácil do que programar para Windows. Em
resumo, a porta serial é um arquivo, de onde você lê e para onde você
escreve.

Vale também a correção que /dev/ttyS0 é porta serial, não paralela. A
paralela é normalmente a /dev/lp. As duas são fundamentalmente
diferentes, porque uma implementa o protocolo RS232 para codificar um
determinado stream de informações, enquanto a porta paralela é
simplesmente um conjunto de pinos que você manipula.

Bom, dito isso, vamos à parte interessante...

Em primeiro lugar, você precisa abrir a porta. Para isso:

  use IO::Handle; # para voce ter API OO para os filehandles
  open my $fh, '+<', '/dev/ttyS0' or die $!;

O '+<' no modo significa que você está abrindo tanto para leitura quanto
para escrita (perldoc -f open é seu amigo). Depois disso, você
provavelmente quer IO não bloqueante, exceto se o seu protocolo for bem
previsível (nunca é). Para isso:

  $fh->blocking(0);

Pode ser necessário você configurar a porta serial, uma vez que o
dispositivo pode não estar usando a mesma configuração padrão que você.
Para isso você precisa do acesso à API POSIX, especificamente ao
termios.h. Então a primeira coisa que você precisa é:

  use POSIX qw(:termios_h);

Então para você configurar a porta, você pode fazer algo do tipo:

    my $term = POSIX::Termios->new;
    $term->getattr(fileno($fh)) or die $!;
    $term->setiflag( $term->getiflag &
      ( &POSIX::IGNBRK | &POSIX::IGNPAR &
        ~&POSIX::INPCK & ~ &POSIX::IXON &
        ~ &POSIX::IXOFF));
    $term->setlflag( $term->getlflag & 
      ~( &POSIX::ICANON | &POSIX::ECHO |
         &POSIX::ECHONL | &POSIX::ISIG |
         &POSIX::IEXTEN ));
    $term->setcflag( $term->getcflag &
      ( &POSIX::CSIZE | &POSIX::CS8 & ~&POSIX::PARENB));
    $term->setospeed(&POSIX::B1200);
    $term->setispeed(&POSIX::B1200);
    $term->setattr(fileno($fh), &POSIX::TCSANOW) or die $!;

perldoc POSIX e man termios (instale o manpages-dev) ajudam a entender o
que isso faz.

Agora você está pronto para ler e escrever da porta serial, mas a não
ser que você tenha um ambiente muito controlado, você não quer fazer
isso de maneira síncrona. Para isso recomendo o módulo EV.

Vou deixar o exercício de como escrever o IO assíncrono com você, eu
acho até que eu já postei um exemplo parecido aqui uma vez...

daniel



Mais detalhes sobre a lista de discussão Cascavel-pm