[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