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

I've got a strange problem with Win32::SerialPort, and could really use some help.

I can't seem to get my Belkin F5U109 serial to USB adapter to take a baudrate setting. My normal serial ports work fine, as does my Radioshack #26-183. This problem is consistant between Windows 2000 and XP.

Of course, the adapter works fine with Hyperterm and Bray's terminal emulator. So the question is what am I doing wrong?

Update: The belkin serial port is configured as a 9600 baud serial port through the device manager. Despite that it defaults to 1200 baud and won't allow me to set the baudrate.

Below you'll find some test code that will demonstrate the behavior, as well as its output.

use strict; use warnings; use Win32::SerialPort; use Getopt::Long; # Strings with comport names my $arg_com_a; my $arg_com_b; GetOptions( 'a:s' => \$arg_com_a, # a should be the Belkin 'b:s' => \$arg_com_b, # we vary b to find out what's up ) or die "Bad command line options\n"; # Create a serial port object for the test my $com_a = Win32::SerialPort->new( $arg_com_a ) or die "Error opening $arg_com_a $!\n"; configure_comport($com_a); my $com_b; # a globalto store the b serial port object in. # Begin testing. foreach my $baudrate (qw( 9600 4800 2400 1200 600 300 )) { print "\nA-$arg_com_a: 9600 \tB-$arg_com_b: $baudrate\n"; print '-'x30 . "\n"; $com_b = Win32::SerialPort->new( $arg_com_b ) or die "Error opening $arg_com_b $!\n"; configure_comport($com_b, $baudrate); $com_b->write_settings; # This fails under XP test_send(); test_recv(); $com_b = undef; } exit; # ================================================================== # test_send ====================================== # Try sending data from A to B. sub test_send { my $test_out = "ABCDEFG 1234567\n"; $com_a->write($test_out); my $test_in = read_data($com_b, 5) || ""; # read_data() excludes the lookfor() characters (in this case \n), + so we chomp to make it possible for the test strings to match chomp $test_out; if ( $test_out eq $test_in ) { print "A TX\tSUCCESS: $test_in\n"; } else { print "A TX\t->$test_out<-\nB RX\t->$test_in<-\n\n"; } } # END test_send ================================== # test_recv ====================================== # Try recieving data sent from B. sub test_recv { my $test_out = "ABCDEFG 1234567\n"; $com_b->write($test_out); my $test_in = read_data($com_a, 5) || ""; # read_data() excludes the lookfor() characters (in this case \n), + so we chomp to make it possible for the test strings to match chomp $test_out; if ( $test_out eq $test_in ) { print "B TX\tSUCCESS: $test_in\n"; } else { print "B TX\t->$test_out<-\nA RX\t->$test_in<-\n\n"; } } # END test_recv ================================== # read_data ====================================== # Attempt to read data from a serial port object. # First argument is a serial port object. # Second argument is the timeout period in seconds. sub read_data { my $p = shift; my $timeout = shift || 1; # Store timeout time in millisecond ticks. $timeout = $p->get_tick_count + (1000 * $timeout); $p->lookclear; # Clear lookfor buffers my $gotit = ""; while(1) { # polls until we have a line of data return unless ( defined ($gotit = $p->streamline) ); if ($gotit ne "") { my ($found, $end, $pattern, $instead) = $p->lastlook; return "$gotit"; } # or an error return if ($p->reset_error); if ($p->get_tick_count > $timeout) { my ($match, $after, $pattern, $instead) = $p->lastlook; return ; } } } # END read_data ================================== # configure_comport ============================== # Apply a standard configuration to a comport. # First argument is a serial port object. # Second argument is baudrate, defaults to 9600. sub configure_comport { my $p = shift; my $baudrate = shift || 9600; $p->baudrate($baudrate); $p->parity('none'); $p->databits(8); $p->stopbits(1); $p->handshake('none'); $p->xon_limit(100); # bytes left in buffer $p->xoff_limit(100); # space left in buffer $p->xon_char(0x11); $p->xoff_char(0x13); $p->eof_char(0x0); $p->event_char(0x0); $p->error_char(0); # for parity errors $p->buffers(4096, 4096); # read, write $p->read_interval(100); # max time between read char (milliseco +nds) $p->read_char_time(5); # avg time between read char $p->read_const_time(100); # total = (avg * bytes) + const $p->write_char_time(5); $p->write_const_time(100); $p->error_msg(1); $p->user_msg(1); $p->binary(1); # Win2K really likes this to be true. # Match line endings. $p->are_match( "\n", ); $p->write_settings; # This fails under XP } # END configure_comport ====================

Here's the output of the script when run with the Belkin adapter at COM5 (COM1 is a real serial port).

Update:To clarify what is happening here, I am varying the baudrate of com port B to determine the actual baud rate of com port A. So, when the output says "A-COM5: 9600 B-COM1: 1200" it means that COM5 was configured as 9600 baud, and COM1 was configured as 1200 baud. A line with SUCCESS means that the sent and recieved data match.

C:\Documents and Settings\Mark\Desktop>serialkiller.pl -a=COM5 -b=COM1

A-COM5: 9600    B-COM1: 9600
------------------------------
Break Signal detected
A TX    ->ABCDEFG 1234567<-
B RX    -><-

B TX    ->ABCDEFG 1234567<-
A RX    -><-


A-COM5: 9600    B-COM1: 4800
------------------------------
Framing Error detected
A TX    ->ABCDEFG 1234567<-
B RX    -><-

B TX    ->ABCDEFG 1234567<-
A RX    -><-


A-COM5: 9600    B-COM1: 2400
------------------------------
Framing Error detected
A TX    ->ABCDEFG 1234567<-
B RX    -><-

B TX    ->ABCDEFG 1234567<-
A RX    -><-


A-COM5: 9600    B-COM1: 1200
------------------------------
A TX    SUCCESS: ABCDEFG 1234567
B TX    SUCCESS: ABCDEFG 1234567

A-COM5: 9600    B-COM1: 600
------------------------------
Framing Error detected
A TX    ->ABCDEFG 1234567<-
B RX    -><-

B TX    ->ABCDEFG 1234567<-
A RX    -><-


A-COM5: 9600    B-COM1: 300
------------------------------
A TX    ->ABCDEFG 1234567<-
B RX    -><-

B TX    ->ABCDEFG 1234567<-
A RX    -><-

Note: Based on graff's comment, I decided that needed clarify what I wrote. I hope the few additional sentences help clear up what the nature of my problem is.


TGI says moo

Replies are listed 'Best First'.
Re: Can't set baudrate with Win32::SerialPort and Belkin USB adapter
by graff (Chancellor) on Sep 24, 2005 at 04:33 UTC
    I'm sorry, but your lead-in description makes me wonder if this is really a hardware question rather than a Perl (or any kind of software) question.

    Does the perl script work as expected when "comport A" is something other than the Belkin USB adapter?

    I gather that the problem is shown at the point in the output where it says "SUCCESS" given that "A-COM5" is supposed to be going at 9600 and "B-COM1" is supposed to be going at 1200 -- which means that "A-COM5" actually must have 1200 as some sort of default pre-set, and when you tried setting it to 9600, it remained at 1200. Is that it?

    If baudrate changes work as expected on the Belkin when this is done by things other than the perl script, and if the perl script succeeds in changing the baudrate on a COM port when some device other than the Belkin is attached, you have my sympathy. Alas, that's all I can offer.

    (Well, maybe you'd have to look up details on things like data bits, stop bits, parity, handshaking, xon/xoff, etc, to see if maybe there's something among that set of parameters that the Belkin doesn't support. I could well imagine a situation where the device would ignore any change request if one of these details were "out-of-spec". Have you verified that these settings in the perl script match the ones you used with Hyperterm, etc?)

      I would write it off as a hardware/driver problem if I other software didn't work.

      So I am left with three possibilities:

      1. My code is wrong
      2. Win32::SerialPort is broken
      3. The belkin drivers are broken (and so W32::SP can't configure the port normally)

      Naturally, my assumption is that 1 is the case. At least until I've looked a bit more at what's happening. It is possible, though, that W32::SP is showing its age, it hasn't been updated in a few years. If 3 is the case, I don't know how I'll ever straighten this out, as I am definitely not an Win32 API guru.


      TGI says moo

Re: Can't set baudrate with Win32::SerialPort and Belkin USB adapter
by TGI (Parson) on Sep 26, 2005 at 21:56 UTC

    I found the solution. The Belkin adapter apparently doesn't return correct information when it is queried for legal baudrates.

    The solution is to munge the Win32API::CommPort object's _L_BAUD record.

    my $p = Win32::SerialPort->new( 'BROKEN_BELKIN_BS' ) or die "Error opening your stupid Belkin adapter $!\n"; $p->{'_L_BAUD'}{9600} = 9600; $p->baudrate(9600); print "Bauds " . $p->baudrate . "\n";


    TGI says moo