Skip Menu |

This queue is for tickets about the IO-Termios CPAN distribution.

Report information
The Basics
Id: 125409
Status: resolved
Priority: 0/
Queue: IO-Termios

People
Owner: Nobody in particular
Requestors: ATHREEF [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: (no value)
Fixed in: 0.06



Subject: Opening serial ports under macOS indefinitely blocks
I run Perl v5.26.1 on macOS 10.13.4 (High Sierra) and want to communicate with the Bus Pirate. I can't reproduce this on Linux, but you probably know that. I wanted to use your Device::BusPirate, but opening the serial port inside IO::Termios->open indefinitely blocks. Looking at the Serial Programming Guide for POSIX Operating Systems: https://www.cmrr.umn.edu/~strupp/serial.html, it seems you are supposed to always open the serial port with O_NDELAY|O_NOCTTY first. Doing so makes the sysopen return, but now the syswrite returns EAGAIN. Following the advice of the guide, I set CLOCAL and CREAD on the fd and now it works as expected. I noticed CREAD doesn't seem necessary in my case, but I rather stick to what's in the guide. I attached an example script that shows what worked for me on macOS. I am using IO::Termios->new, but it would be nice if IO::Termios->open could do this as well, as it seems to me that would be the more portable approach. Script ran successfully on Linux as well.
Subject: termios.pl
#!/usr/bin/env perl use strict; use warnings; use IO::Termios; use Fcntl; use IO::Select; $|++; my $serial = $ENV{BUS_PIRATE} || "/dev/tty.usbserial-A603PKBX"; my $baud = 115200; sysopen my $fd, $serial, O_RDWR|O_NDELAY|O_NOCTTY or die "Cannot open serial port $serial - $!"; my $fh = IO::Termios->new($fd) or die "Cannot wrap serial port $serial - $!"; $fh->set_mode( "$baud,8,n,1" ) or die "Cannot set mode on serial port $serial"; $fh->setflag_icanon( 0 ); $fh->setflag_echo( 0 ); $fh->blocking( 0 ); $fh->setflag_clocal( 1 ); $fh->setflag_cread( 1 ); print "Writing..."; if (IO::Select->new($fh)->can_write) { $fh->syswrite("\r\n") or die "Error writing to serial port - $!"; print " [DONE]\n"; } print "Reading..."; my $buf; if (IO::Select->new($fh)->can_read) { $fh->sysread($buf, 6) or die "Error reading from serial port - $!"; print " [DONE]\n" } die "Unexpected output: `$buf'\n" if $buf !~ /HiZ>$/; print "All is well!\n";
On Sun May 27 03:05:46 2018, ATHREEF wrote: Show quoted text
> I wanted to use your Device::BusPirate, but opening the serial port > inside IO::Termios->open indefinitely blocks. > Looking at the Serial Programming Guide for POSIX Operating Systems: > https://www.cmrr.umn.edu/~strupp/serial.html, > it seems you are supposed to always open the serial port with > O_NDELAY|O_NOCTTY first. Doing so makes the sysopen return, but now > the syswrite returns EAGAIN. > > Following the advice of the guide, I set CLOCAL and CREAD on the fd > and now it works as expected. I noticed CREAD doesn't seem necessary > in my case, but I rather stick to what's in the guide.
Ah yes; you are correct there. This is Linux being a bit sloppy with its interpretation in order to be "helpful", but in doing so causes programmers not to realise the bugs in their own implementation. In summary: this all relates to the DTR/DSR handshaking lines, which the Bus Pirate doesn't use. open(2) is supposed to block until the "data set" (i.e. modem or other device) indicates that it is ready - hence DSR. The O_NDELAY flag prevents that, and defers the block to the first read/write call. Setting the CLOCAL termios flag then tells it not to bother because we're working with a "local" device, and hence all now works. I should indeed make sure to use O_NDELAY and set CLOCAL, as you find is necessary. Show quoted text
> I attached an example script that shows what worked for me on macOS. I > am using IO::Termios->new, but it would be nice if IO::Termios->open > could do this as well, as it seems to me that would be the more > portable approach. Script ran successfully on Linux as well.
I'll compare that to what I believe should be the minimum required, and suggest you a new version that might help. I'm unsure yet whether it'll be a new version of IO::Termios or Device::BusPirate directly, so I may have to move this bug to a different queue. -- Paul Evans
On Mon Jun 04 11:56:46 2018, PEVANS wrote: Show quoted text
> In summary: this all relates to the DTR/DSR handshaking lines, which > the Bus Pirate doesn't use. open(2) is supposed to block until the > "data set" (i.e. modem or other device) indicates that it is ready - > hence DSR. The O_NDELAY flag prevents that, and defers the block to > the first read/write call. Setting the CLOCAL termios flag then tells > it not to bother because we're working with a "local" device, and > hence all now works.
Ah; hmm. Some sources suggest it's the DCD line actually, not DSR. But either way, the Bus Pirate doesn't drive those. Show quoted text
> I'll compare that to what I believe should be the minimum required, > and suggest you a new version that might help. > > I'm unsure yet whether it'll be a new version of IO::Termios or > Device::BusPirate directly, so I may have to move this bug to a > different queue.
New version of IO::Termios 0.06 on CPAN that adds ability to supply more open flags. Combine that with the-attached patch to Device/BusPirate.pm itself, and hopefully that should now be working for you. -- Paul Evans
Subject: rt125409.patch
=== modified file 'lib/Device/BusPirate.pm' --- lib/Device/BusPirate.pm 2018-06-04 16:35:31 +0000 +++ lib/Device/BusPirate.pm 2018-06-04 21:40:58 +0000 @@ -12,9 +12,10 @@ use Carp; +use Fcntl qw( O_NOCTTY O_NDELAY ); use Future::Mutex; use Future::Utils qw( repeat ); -use IO::Termios; +use IO::Termios 0.06; use Time::HiRes qw( time ); use Module::Pluggable @@ -110,9 +111,10 @@ my $serial = $args{serial} || BUS_PIRATE; my $baud = $args{baud} || 115200; - my $fh = IO::Termios->open( $serial, "$baud,8,n,1" ) + my $fh = IO::Termios->open( $serial, "$baud,8,n,1", O_NOCTTY|O_NDELAY ) or croak "Cannot open serial port $serial - $!"; + $fh->setflag_clocal( 1 ); $fh->setflag_icanon( 0 ); $fh->setflag_echo( 0 );
Am Di 05. Jun 2018, 08:24:01, PEVANS schrieb: Show quoted text
> New version of IO::Termios 0.06 on CPAN that adds ability to supply > more open flags. Combine that with the-attached patch to > Device/BusPirate.pm itself, and hopefully that should now be working > for you.
Works. Could you prepare a release? Thanks!
Fixed by Device::BusPirate 0.15, which uses IO::Termios 0.06. -- Paul Evans
Am Mi 06. Jun 2018, 06:26:06, PEVANS schrieb: Show quoted text
> Fixed by Device::BusPirate 0.15, which uses IO::Termios 0.06.
Thanks you! Just pushed a package (Device::GBA) depending on the new Device::BusPirate. :)