Sec has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I have some old perl code that talks to a serial interface. It was using IO::Stty to set some modes. Unfortunately after some upgrades, this code now stopped working:

open(Client,"+>/dev/ttyUSB0") || die "open: $!"; use IO::Stty; IO::Stty::stty(\*Client,"-crtscts"); IO::Stty::stty(\*Client,"19200"); IO::Stty::stty(\*Client,"-echo"); IO::Stty::stty(\*Client,"-icrnl");
this is the result:
IO::Stty::stty passed invalid parameter 'crtscts' Can't use string ("POSIX::B19200") as a subroutine ref while "strict r +efs" in use at /usr/share/perl5/IO/Stty.pm line 567.
Some googling turned up rt://97576 which suggests that IO:Stty has been abandoned.

Does anyone have a suggestion on how to to id properly? My fallback solution is to just system() stty...

Replies are listed 'Best First'.
Re: How to set tty settings from perl
by haukex (Archbishop) on Dec 08, 2019 at 21:39 UTC
    Unfortunately after some upgrades, this code now stopped working

    That's strange, it doesn't seem like IO::Stty ever supported crtscts.

    Does anyone have a suggestion on how to to id properly?

    Well, if you look at the source, what the module is doing is mostly tedious, but not too complex. You could set attributes on the port using your own POSIX::Termios object.

    You might also be interested in my node Lower-Level Serial Port Access on *NIX; I've been using IO::Termios with good success (also in combination with IO::Stty).

    open(Client,"+>/dev/ttyUSB0") || die "open: $!";

    BTW, see "open" Best Practices.

    My fallback solution is to just system() stty...

    Yes, in the worst case that's a possibility, I am guessing this code isn't meant to be super portable anyway. I'd recommend using a module instead of plain system, I showed some examples here.

      Thanks for your suggestion of IO::Termios. Unfortunately it seems that the OS in question (ubuntu) lacks packages for IO::Termios.

      I may be that crtscts never worked, can't really check right now. But it definitely didn't die while setting 19200, which it now does.

      Your comment on open is duly noted, but as stated, the code is _OLD_ (written in 2000) and I didn't really plan to rewrite it :-)

      Lastly, I looked at your link about system -- maybe I'm missing something, but system(LIST) seems to be just fine?

        Unfortunately it seems that the OS in question (ubuntu) lacks packages for IO::Termios.

        Yes, IO::Termios needs to be installed from CPAN, using e.g. cpanm, although installing modules into the system Perl has the caveats that uninstallation is tricky and it may clash with modules installed using the system's package manager. You could consider local::lib or even perlbrew, and it's also possible to install modules to some other global directory where they won't clash with modules installed by the system package manager (depending on the distro, that could be something like perhaps /usr/local/lib/site_perl, check your perl -V output for the preconfigured @INC).

        But it definitely didn't die while setting 19200, which it now does.

        Yes, that is indeed strange. Can you say what the old and new versions of IO::Stty and Perl were?

        Lastly, I looked at your link about system -- maybe I'm missing something, but system(LIST) seems to be just fine?

        Well, on a *NIX system the system(LIST) form should be "safe". Using a module gives you the advantage of built-in error handling (e.g. IPC::System::Simple, which has a drop-in replacement for system), or the ability to capture STDOUT/ERR in case you want to hide it from the user or inspect it for error messages (e.g. IPC::Run3). If you don't care about those things, then yes, system(LIST) where LIST has two or more elements is fine.

        (BTW, an open mode of +> will clobber the file first - for a serial port it's probably fine, but for regular files you would probably want +< for read-write access instead.)