Dr. Mu has asked for the wisdom of the Perl Monks concerning the following question:
I use the following code to open the port:
Before the program exits after a normal, working run, the following subroutine is executed:$PortName = 'COM1'; $Baudrate = 9600; while ($cmd = shift @ARGV) { $PortName = shift @ARGV if $cmd eq '-p'; $Baudrate = shift @ARGV if $cmd eq '-b' } unless ($Port = new Win32::SerialPort($PortName) and $Port->are_baudrate(115200) and $Port->baudrate($Baudrate) and $Port->parity('none') and $Port->databits(8) and $Port->stopbits(2) and $Port->handshake('rts') and $Port->buffers(4096,4096) and $Port->binary(1) and $Port->xon_limit(3000) and $Port->xoff_limit(300) and $Port->rts_active(1) and $Port->write_settings) { $mw->messageBox( -message => "Can't open $PortName at $Baudrate baud.", -type => 'OK' ); print $^E; exit }
This subroutine was added in a vain attempt to make sure the port is cleared and closed properly before exiting. It wasn't needed under Win98. I never get the "Close failed" warning, BTW. If anyone can see what I've apparently failed so far to see, I (and my customer) would be very grateful. Thanks.sub PowerDown { $Port->rts_active(0); $Port->write_settings; Win32::Sleep(1000); $Port->read; $Port->close || warn "Close failed.\n"; undef $Port; exit }
Update: I suspected that the error I was getting had something to do with handshaking, i.e. that the port was getting closed with characters remaining in the transmit buffer, awaiting a CTS from the equipment it's connected to. To test this theory, I rewrote the PowerDown subroutine as follows:
This solved the problem -- sort of. I don't get an error anymore when I open the port on the second go'round. But I do get a "Buffer Overrun" error after it's open and a bunch of data left over from the last time the port was opened. Also, on shutdown, I occasionally get a window manager protocol error from Tk. (I'm using WM_DELETE_WINDOW to intercept the intent to exit.) That's probably harmless, but there's got to be a cleaner, more reliable way to do this...sub PowerDown { $Port->handshake('none'); $Port->rts_active(0); $Port->write_settings; Win32::Sleep(1000); $Port->read; $Port->close || warn "Close failed.\n"; undef $Port; exit }
Update 2: I think I may have gotten to the root of the problem. Buried in the "Bugs" section of the Win32::SerialPort docs is the statement, "On NT, a read_done or write_done returns False if a background operation is aborted by a purge. Win95 returns True." Without the above modified PowerDown routine, a purge is likely what Perl performs on the port when it exits, leaving it in a non-write_done state. Assuming that Perl uses these flags to determine whether the port can reopen, the error message I was getting makes perfect sense. On the other hand, other non-Perl apps are not so constrained and are perfectly happy to open the port anyway. So my question is, rather than requiring programmers to go through the gyrations outlined above to close an open port so it's not left in a closed-but-not-really limbo, why not simply make the module more forgiving on opening the port, as other programming environments evidently do?
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Win32::SerialPort Error: Overlapped-I/O operation is in progress ($^E too late)
by tye (Sage) on Mar 27, 2005 at 21:39 UTC | |
by Dr. Mu (Hermit) on Mar 27, 2005 at 22:13 UTC | |
by ikegami (Patriarch) on Mar 28, 2005 at 02:35 UTC | |
by Dr. Mu (Hermit) on Mar 28, 2005 at 07:53 UTC | |
|
Re: Win32::SerialPort Error: Overlapped-I/O operation is in progress
by dcd (Scribe) on Mar 29, 2005 at 02:29 UTC | |
by Anonymous Monk on Mar 30, 2005 at 03:08 UTC | |
by Dr. Mu (Hermit) on Mar 30, 2005 at 06:59 UTC |