Sériový port v PERLu

02.02.2007

Včera jsem potřeboval v jednom perlivém modulu vyřešit komunikaci se sériovým portem v Linuxu. Inu, řešení se nabízí přímo samo a to komunikovat přímo s /dev/ttySn jako s obyčejným souborem. Jde to, ale dře to, hlavně při pohledu na manuálovou stránku programu stty, který slouží k nastavování všemožných parametrů sériového portu.

PERLivý svět však disponuje nepřeberným množstvím předvařených modulů řešící všemožné záludnosti tohoto světa a shodou okolností je mezi nimi i modul Device::SerialPort. Ovšem jeho manuálová stránka je krize sama o sobě, nelhledě na přibalené expamles. A přitom mi šlo o jediné: vyslat řetězec a přijmout řetezec :-) Takovou "záludnost" jsem v Delphi řešil 20 sekund vyhledáním metody ReadString a SendString. Zde nic takového není a tak jsem spláncul něco velmi jednoduchého, jen tak na test, že to jde. A to je výsledek. Třeba vám pomůže.

Pokud modul Device::SerialPort na svém stroji nemáte, řešení je perl -MCPAN -e 'install Device::SerialPort'

        #!/usr/bin/perl -w
        
        use Device::SerialPort qw( :PARAM :STAT 0.07 );
        
        # Otevreni portu / instance tridy Device::SerialPort
        $port=Device::SerialPort->new("/dev/ttyS0");
        # Nastaveni parametru portu
        # Rychlost: 2400, 4800, 9600 apod.. klasika
        $port->baudrate(9600);
        # Parita: node, odd, even 
        $port->parity("none");
        # Datovych bitu na ramec, obvykle 8
        $port->databits(8);
        # Pocet stop bitu, obvykle 1, nekdy 2
        $port->stopbits(1);
        # Rizeni provozu: none, xon, xoff
        $port->handshake("none");
        # Jak dlouho se ma cekat na dalsi znak. To zde neresime.
        $port->read_char_time(0);
        # Jak dlouho se ma z portu prijimat v ms, zde 1 sec
        $port->read_const_time(1000);
        
        
        # Posle na port text AHOJ SVETE a ukonci ho znakem \n
        $port->write("AHOJ SVETE\n");
        # Bude cekat 10 sekund na odpoved ze serioveho portu. Pokud odpoved prijde, vypise ji. 
        $vysledek=&readstring(10);
        print "Ze serioveho portu prislo: $vysledek";
        
        # Podprogram na cteni retezce se serioveho portu. Periodicky testuje prichozi data a pokud
        # se objevi retezec obsahujici \n\r, cekani ukocni, retezec orizne a vrati. Jinak napise timeout.
        # Perioda je dana parametrem read_const_time a to je v tomto pripade 1 sekunda. 
        # Delka nacteneho reteze je max. 253 znaku a musi byt vzdy ukoncen \n\r viz reg. vyrazy.
        sub readstring {
          my ($timeout) = @_;
          my ($buffer,$saw,$count);
          $buffer="";
          $saw="";
          while (($timeout>0)&&($saw !~ /[\n\r]/)) {
            ($count,$saw)=$port->read(255);
            $buffer.=$saw;
            $timeout--;
          }
          $buffer =~ s/[\n\r].*//g;
          if($timeout==0) {print "timeout";}
          return($buffer);
        }