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

I am trying to script communication with a USB Serial port (COM9) on windows. I found this link but it is 7 years old. Any chance there is a solution out there now?

I have tried Win32::SerialPort but it fails with an error "invalid COMMPROP block length= 66".

use Win32::SerialPort; use strict; use warnings; my $Port = "COM9"; # port to watch my $Baud=15200; my $PortObj = Win32::SerialPort->new ($Port,1) || die "Can't Open $Por +t: $!"; $PortObj->write_settings || undef $PortObj; print "Can't change Device_Control_Block: $^E\n" unless ($PortObj); $PortObj->baudrate($Baud) || die "failed setting baudrate to $Baud"; $PortObj->parity("none") || die "failed setting parity"; $PortObj->databits(8) || die "failed setting databits"; $PortObj->handshake("none") || die "failed setting handshake"; my $rtn=$PortObj->write("help"); print $rtn; sleep 1; print "DONE\n"; undef $PortObj; exit;

I have tried Device::USB but it does not seem to support USB devices on windows.

I have tried to use sysopen and syswrite (code below) but I am now sure how to get to to do anything for me. I hangs on the sysread. Plus I am not sure how to set the baudrate,etc with this method.

#!perl $port="COM9"; sysopen(COM,$port,O_RDWR) || die "Can't open $port $^E"; $length=1024; while(1){ print ">"; $cmd=<STDIN>; if($cmd=~/^(x|q|exit|quit)$/is){last;} $cmd =~s/[\r\n]+$//; print "Cmd: $cmd\n"; my $packcmd=pack("A*",$cmd); print "Send: $packcmd\n"; syswrite(COM,$packcmd); #sends $string to COM1 print "Reading...\n"; #code to read data from port sysread(COM,$buf,$length); #read $length bytes print "Buf: $buf\n"; $received = unpack("C*",$buf); #unpack them print "Receive: $received\n"; } exit;
Any help would be greatly appreciated. If I use hyperterminal, I can simply choose COM9 and set the baudrate to 115200 and I connect fine.
s/te/ve/

Replies are listed 'Best First'.
Re: Connecting to a USB Serial Device on Windows
by GrandFather (Saint) on Jul 10, 2009 at 02:18 UTC

    Ignore the USB aspect of the connection. At either end of the USB link you are simply dealing with an RS232 serial port - everything else should be taken care of 'under the hood'. That said, the 'under the hood' stuff is tricky and it may be that you have been bitten by a bad implementation.

    More likely however: "invalid COMMPROP block length" sounds like a Windows API related error (COMMPROP is a structure used by the serial port API calls). It may be that the API has moved on since Win32::SerialPort was last worked on and dodgy stuff that used to work now fails on newer versions of Windows. You could use Win32::API and effectively reinvent the Win32API::CommPort wheel, or you could try to track down the bug in Win32API::CommPort / Win32::SerialPort. Unless you are somewhat familiar with the Win32 API either option is likely to entail something of a steep learning curve. Otherwise, I suspect you are a bit stuffed!


    True laziness is hard work
      Wahoo! After a bit of goofing around and some pure luck I was able to make it work. I modified Win32::ComPort.pm, increasing the CP_Length from 64 to 66 as follows:
      if (($CP_Length > 64) and ($self->{"_TYPE"} == PST_RS232)) {
      to
      if (($CP_Length > 66) and ($self->{"_TYPE"} == PST_RS232)) {
      Then I installed Device::Modem and wrote the following:
      #!perl use strict; #http://search.cpan.org/~cosimo/Device-Modem-1.51/ use Device::Modem; my $port="COM9"; my $modem = new Device::Modem( port =>$port ); if($modem->connect( baudrate => 115200,databits=>8,parity=>'none',stop +bits=>1 ) ) { print "connected!\n"; } else{ print "Error: Unable to connect with $port!.\n\t$!\n"; exit; } print "CMD->"; while(1){ my $cmd=<STDIN>; if($cmd=~/^(x|q|exit|quit)$/is){last;} $cmd =~s/[\r\n\t\s]+$//; $cmd =~s/^[\r\n\t\s]+//; $modem->atsend($cmd . Device::Modem::CR); print $modem->answer(); } #disconnect from the Modem $modem->disconnect(); print "\nDONE\n";
      And it all works. I am able to communicate to my usb device, passing it commands and seeing the returning answer. Wahoo!
      s/te/ve/

        Very well done! There is actually already a bug report (#33559) at rt://Win32-SerialPort and the module author (or someone) has replied. The two other people who experienced the problem did what you have done with mixed success. It might not hurt to add your two bits worth in the hope that the module author can find a general solution to the issue and at least knows that a) there are people using the module, and b) people are seeing the same problem (module authors like feedback, even / especially bug reports).


        True laziness is hard work
        Changes to Win32::ComPort.pm worked for me too. Thank you very much
        I ran into the same error message. Changes made to the Win32::ComPort.pm file definitely made things work. THANKS!