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

Hey guys,
First a quick bit of context:
I am venturing into WindowsLand (Edit : Windows XP ) and I need to write something that will periodically (1 second) look at a serial port, and if there is one plugged in will start polling it and stashing the data received.

Initially I wrote something that uses Win32::SerialPort, creates a $PortObj, polls every second, and does exactly what I want it to.

The added complexity comes when I want to have the plug in plug out capabilities.

So, using Win32::Daemon I wrote something that looks every second at the port, and can detect whenever anything is plugged in or plugged out. Whenever something is plugged in, the Daemon creates a PortObj and works away.

However, when the device is unplugged, the Daemon realises, and runs
$PortObj->close || warn "Oh Noes! No close!"; undef $PortObj;

I receive no warnings. The $PortObj exists still, and seems to close properly (even though the physical connection has been pulled).
Then, when my Daemon see's a connection again, I try to create a new $PortObj I get "Access to Port COMX is denied" and general borkage.
If I try to open and close and then reopen $PortObj without unplugging the device there is no problem.
I do note that in the documentation, under the Bugs section, there is a note (and I quote from http://search.cpan.org/~bbirth/Win32-SerialPort-0.19/lib/Win32/SerialPort.pm#BUGS)

"On Win32, a port must close before it can be reopened again by the same process. If a physical port can be accessed using more than one name (see above), all names are treated as one. The perl script can also be run multiple times within a single batch file or shell script. The Makefile.PL spawns subshells with backticks to run the test suite on Perl 5.003 - ugly, but it works."

To me there appears to be something hairy going on with the dealloc of resources between Perl and Windows that I am screwing up because of my device being pulled. It seems like the close is not working properly despite the lack of warnings being kicked out.

But, basically I just need this to work. Elegance need not be an issue at the moment. I considered doing something like the tail of the doc says, and stop the Daemon when I see the connect go away, but then how do I start it again to look for new connects? (Unless I write another Daemon that runs the portd ???)

I dunno. I have a suspicion that you lot may be smarter than me, and one of you is going to be able to whip out a single LOC that will force the freeing of the COM port and allow perl to grab it again. Any ideas? (Also, seeing as this is my fp here, I should take a second to thank all of you for your excellent site, on which I have been lurking all over for years.)

Replies are listed 'Best First'.
Re: Win32::SerialPort ; close / open problem
by GrandFather (Saint) on Jul 25, 2009 at 22:51 UTC

    'RS-232' serial ports do not provide any hardware connected detection beyond handshake lines being in the correct state. Plugging and unplugging a serial cable does not affect the state of any software or drivers that is associated with the port. So for 'RS-232' ports there is no need to open/close the port because the cable has been connected/disconnected or the device at the far end of the cable has been turned on/off.

    However, if you are using a USB/RS-232 device and it is the USB cable that is being plugged/unplugged, then you are in a whole different world and there may be nasty stuff going on that you have no control over. The OS's RS-232 drivers were not designed with the serial port hardware coming and going - the hardware was either on the mother or plugged in through a hardware buss so that just couldn't happen. As a result bad stuff can happen in the context of USB/RS-232 devices because they try to look like legacy serial ports to the OS, but don't behave like them. I wouldn't be surprised to see bad behaviour especially during connect and disconnect and that there may be no simple solution.


    True laziness is hard work
      Thanks Grandfather, right, I'm using a USB/RS-232 device.
      Hmm. No simple solution... I had a feeling this might be the case.
      I was just reading through the Win32API::CommPort docs, there is a section for Raw Win32 system API, but none of it seems to be useful for me.
      Maybe I can have a separate listener Daemon just start and stop the PortObj Daemon. When the Daemon gets stopped it can release whatever lock is in place. I'll have to try and find a Windows machine at home to test this theory.

        I suggest that if possible never disconnect the USB cable, but instead connect/disconnect the serial cable and use the state of handshake lines or the cessation/resumption of data flow to indicate the connect/disconnect. You are stymied if the 'serial port' is internal to a hardware device however and you can't break the serial connection.

        Maybe you need to tell us a little more about the bigger picture for better advice? In particular, why are devices connected and disconnected and what sort of device are thy?


        True laziness is hard work