in reply to Windows serial I/O

I e-mailed this question to Bill Birthisel, the author of Win32::SerialPort and Win32API::CommPort. My original query and his answer (with his permission) follow:

______________________

I'm trying to open COM1 at 115200 baud on a Win98 machine using Win32::SerialPort. After first rebooting, I cannot. In fact, can_baud(115200) returns false, and are_baudrate omits 115200. Other baudrates, up to 38400, work fine. If I then go to HyperTerminal, I can open the same port at 115200, no problem. What's more, if I close the port, then exit H-T and return to my Perl program, it too will open COM1 at 115200 baud -- at least until I change baud rates. Then I need to go back to H-T to set up the port again. I'm using the latest versions of both Win32API::CommPort and Win32::SerialPort.

<GIGGLE>
True, Win9x does not consider 115200 and 57600 legal rates. It DOES accept 56000. This is a long-standing bug in the Windows API which Microsoft has decided not to fix. In the original concept, only TAPI could request the highest rates because "standard serial ports" (8250s/16450s) couldn't keep up. Of course, that doesn't explain 56000 (NT/2000 uses the correct 57600 and also allows 115200).
</GIGGLE>

So I'm wondering: What's happening here? What's HyperTerminal doing to gain access at 115200 baud that Perl can't do on its own?

It is ignoring the baud-rate validation feature in the API.

Can I get around this by altering the DCB using Win32API::CommPort?

Yes.

Should I? Is there a better way? So many questions!

You can try what I suggested to someone else (who didn't confirm it worked, so consider it an experiment):

In CommPort.pm, change the are_baudrate routine to the following:

sub are_baudrate { my $self = shift; return unless $self->{"_C_BAUD"}; if (@_) { my $newbaud = shift; $self->{"_L_BAUD"}{$newbaud} = $newbaud; } return keys(%{$self->{"_L_BAUD"}}); }

Then '@allowed = $PortObj->are_baudrate(115200);' should add it to the "allowed" list. A real implementation should have a bit more validation and error handling. Let me know if it works.

-bill

______________________

I pasted it in directly from his e-mail, and it worked great!

My code now reads:

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' ); exit }

Many thanks to Bill and the Monks for their time and effort on this one!

-Phil