I am attempting to write code that sets the RTS pin high and waits
until the CD goes low. Then I want to read raw binary data until the
CD goes high. The data being sent at 2400 Baud (8N1). From what I can
glean - this isn't really a handshaking scheme per se, but some sort
of modified one. I am looking for 9 bytes and the first one is always
supposed to be 0x54.
I can't seem to figure out how to
1) Set RTS high/low
2) Detect CD high/low
3) Capture raw binary data (i.e. 0x01, 0x00, etc.)
Can this be done with Perl?? I looked at Win32API::CommPort and these
lower level functions look like the right thing, but I still can't
figure out the afterfore mentioned things.
What sort issues do I have to worry about if I want to do the same
under Linux?
--David Goldman
> I can't seem to figure out how to
The following info is from the manpage of Device::SerialPort (which should
be similar or identical to Win32::SerialPort but I don't use Windows much)
under "Operating Methods". Does the Win32::SerialPort manpage not have
these?
> 1) Set RTS high/low
(set no handshaking when you open the port first)
$PortObj->rts_active(Yes); # return status of ioctl call
# return undef on failure
> 2) Detect CD high/low
$ModemStatus = $PortObj->modemlines;
if ($ModemStatus & $PortObj->MS_RLSD_ON) { print "carrier detected"; }
> 3) Capture raw binary data (i.e. 0x01, 0x00, etc.)
($count_in, $string_in) = $PortObj->read($InBytes);
warn "read unsuccessful\n" unless ($count_in == $InBytes);
> Can this be done with Perl?? I looked at Win32API::CommPort and these
> lower level functions look like the right thing, but I still can't
> figure out the afterfore mentioned things.
>
> What sort issues do I have to worry about if I want to do the same
> under Linux?
Use Device::SerialPort instead of Win32::SerialPort.
Here's a little tidbit that might help:
# Lets serial port programs written for either Windows or Unix
# work on the other kind of system without modification.
# By Ned Konz, n...@bike-nomad.com, http://bike-nomad.com
# This script must have only LF line endings to work cross-platform.
# usage:
# perl -MAnySerialPort myProgram.pl
#
# This will map port names between Linux and Windows; if your system doesn't
# use the same mappings, you can call
# Device::SerialPort::mapPorts
# or
# Win32::SerialPort::mapPorts
# to change it:
# Device::SerialPort->mapPorts('COM1:' => '/dev/magicSerial0',
# 'COM2' => '/dev/magicSerial1');
use strict;
package AnySerialPort;
use vars '@ISA';
BEGIN {
my %portMap;
my $oldNew;
my $onWindows = 0;
if ($^O eq 'MSWin32') # running on Win32
{
$onWindows = 1;
eval "use Win32::SerialPort";
*main::Device::SerialPort:: = *main::Win32::SerialPort::;
$oldNew = \&Win32::SerialPort::new;
$INC{'Device/SerialPort.pm'} = $INC{'Win32/SerialPort.pm'};
%portMap = ('/dev/ttyS0' => 'COM1:',
'/dev/ttyS1' => 'COM2:',
'/dev/ttyS2' => 'COM3:',
'/dev/ttyS3' => 'COM4:',
);
}
else # running on Unix
{
eval "use Device::SerialPort";
*main::Win32::SerialPort:: = *main::Device::SerialPort::;
$oldNew = \&Device::SerialPort::new;
$INC{'Win32/SerialPort.pm'} = $INC{'Device/SerialPort.pm'};
%portMap = ('COM1:'=> '/dev/ttyS0',
'COM2:'=> '/dev/ttyS1',
'COM3:'=> '/dev/ttyS2',
'COM4:'=> '/dev/ttyS3',
);
}
die "$@\n" if $@;
@ISA = 'Device::SerialPort';
# Hook the constructor so we can map the port names
# and class if needed
*main::Device::SerialPort::new = sub {
my $class = shift;
my $portName = shift;
if ($onWindows != ($class eq 'Win32::SerialPort'))
{
$portName = $portMap{$portName} || $portName;
$class = $onWindows ? 'Win32::SerialPort' : 'Device::SerialPort';
}
$oldNew->($class, $portName, @_);
};
# Gets and/or modifies the port mapping
# Returns a hash
sub Device::SerialPort::mapPorts
{
my $self = shift;
%portMap = (%portMap, @_);
}
}
1;
As for $ModemStatus = $PortObj->modemlines;
if ($ModemStatus & $PortObj->MS_RLSD_ON) { print "carrier
detected"; }
I'm not sure what $PortObj->modemlines does - I'm not using a modem,
so I guess I need to understand that before I can use it. If I look at
what $PortObj->MS_RLSD_ON returns - it's always 128 which seems
incorrect as I don't always have the carrier signal high.
-- David
> Thanks for the response. From what I understand the
> $PortObj->rts_active(Yes) call only returns the status of the API
> call, it does not set the state of the bit.
Which API do you think it calls?
> As for $ModemStatus = $PortObj->modemlines;
> if ($ModemStatus & $PortObj->MS_RLSD_ON) { print "carrier
> detected"; }
>
> I'm not sure what $PortObj->modemlines does - I'm not using a modem,
> so I guess I need to understand that before I can use it. If I look at
> what $PortObj->MS_RLSD_ON returns - it's always 128 which seems
> incorrect as I don't always have the carrier signal high.
The modem control and status lines (DCD, RTS, DTR, etc.) don't care whether
or not you have a modem. modemlines() returns the state of the modemlines,
and you just mask the bit(s) you need.
Of course MS_RLSD_ON always returns a 128; it's a bitmask constant that you
just bitwise-AND with the modemlines() return value, as I showed.
I just realized what you meant by MS_RLSD_ON being a bitmask, etc. I
will attempt to use this later today. How is one supposed to know
that's what this thing is? Do you just get divine inspiration? I'm
really trying hard to learn how to learn where to get information like
this. Any suggestions. As for the API call - all I got from the
WIN32::CommPort manpage
(http://members.aol.com/Bbirthisel/CommPort.html) was this -
# controlling outputs from the port
$PortObj->dtr_active(T); # sends outputs direct to
hardware
$PortObj->rts_active(Yes); # returns status of API call
$PortObj->break_active(N); # NOT state of bit
So, I'm still not sure what API this is. Any clues?
Thanks again - David