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

Dear Bretheren, is there a way to poll/find a working serial port in the system without crashing it? My Linux setup works just fine, however, once I'm on Win32 everything crashes!?

sub connect{ if ($os =~ /Win/i){ #this only works with COM1 my @ports_win = ('COM1'); foreach (@ports_win){ open_uart($_); last if ($PortObj); } } else { #This works great my @ports = ('/dev/ttyUSB0','/dev/ttyUSB1','/dev/ttyUSB2','/dev/ +ttyUSB3','/dev/ttyUSB4','/dev/ttyUSB5','/dev/ttyUSB6'); foreach (@ports){ open_uart($_); last if ($PortObj); } } } } sub open_uart { $port_to_open = shift; &attempt($port_to_open); if ($port_not_opening){ #try to connect! for (my $i=1; $i<=15; $i++){ &attempt($port_to_open); print "trying to connect $i\n"; last unless ($port_not_opening); } } return if ($port_not_opening); $PortObj->is_rs232; $PortObj->handshake("none"); $PortObj->user_msg(1); $PortObj->baudrate($conn_speed); $PortObj->parity("none"); $PortObj->databits(8); $PortObj->stopbits(1); $PortObj->read_const_time(500); # 500 milliseconds = 0.5 + seconds $PortObj->read_char_time(500); #was 5 # avg time betwe +en read char $PortObj->buffers(4096, 4096); # read, write $PortObj->parity_enable(1); $PortObj->write_settings || undef $PortObj; #print "Can't change Device_Control_Block: $^E\n" unless ($Por +tObj); } sub attempt { $port_to_open = shift; $port_not_opening =""; if ($os =~ /Win/i){ #win32 eval { $PortObj = new Win32::SerialPort ($port_to_ope +n) or $port_not_opening = $port_to_open; }; } else { #linux eval { $PortObj = new Device::SerialPort ("$port_to_o +pen") or $port_not_opening = $port_to_open; }; } }

Replies are listed 'Best First'.
Re: finding a serial port with Win32::SerialPort
by Marshall (Canon) on Aug 22, 2011 at 10:20 UTC
    Well this dog just doesn't hunt.
    I don't see any code that searches for a COM port.
    sub connect { if ($os =~ /Win/i) { #this only works with COM1 ? Huh? # my @ports_win = ('COM1'); foreach ('COM1') #same as foreach (@ports_win){} { open_uart($_); } } }
      Yes, because my @ports_win = ('COM5', 'COM4','COM1', 'COM2',); crashes a win32 system
        Yes, using the code from AnonMonk...

        You have to ask Win32 what the names of the COM ports are or probe up to a certain COMxx number.

        There are USB ports that can show up as COM ports and I don't know how to create a complete list. I think its hard to do because a new COM port can just "show up" dynamically (i.e. when you plug in a new USB device).

        This may not be right, but this is what it does on my machine.

        #!/usr/bin/perl -w use strict; use Data::Dumper; use Win32::SerialPort; use Win32::OLE('in'); use constant wbemFlagReturnImmediately => 0x10; use constant wbemFlagForwardOnly => 0x20; my $computer = "."; my $objWMIService = Win32::OLE->GetObject ("winmgmts:\\\\$computer\\root\\CIMV2") or die "WMI connection failed.\n"; my $colItems = $objWMIService->ExecQuery ("SELECT * FROM Win32_SerialPortConfiguration", "WQL",wbemFlagReturnImmediately | wbemFlagForwardOnly); foreach my $objItem (in $colItems) { print "Caption: $objItem->{Caption}\n"; print "Name: $objItem->{Name}\n"; } __END__ prints: Caption: COM1 Name: COM1
        I think perhaps another possibility is to "probe COM ports". Use a block "eval" on the "open_uart($_);" statement. >br> Run through the first 32 ports. If a port works works then $_ is a valid COM port and push it onto some stack.

        my @valid_com_ports; foreach my $com ( map{"COM$_"}1..32) { # decide if this $com is ok or not.. # perhaps use the open_uart function() # and then push @valid_com_ports, $com; }
Re: finding a serial port with Win32::SerialPort
by ajose (Acolyte) on Aug 25, 2011 at 18:58 UTC

    I think you should try Hardware::PortScanner for scanning the active COM ports. This works for both Win32 and *nix.