Hardware-PortScanner
view release on metacpan or search on metacpan
PortScanner.pm view on Meta::CPAN
}
sub num_found_devices($) {
my $serial = shift;
return defined( $serial->{FOUND_DEVICE} ) ? scalar( @{ $serial->{FOUND_DEVICE} } ) : 0;
}
sub found_devices($) {
my $serial = shift;
return defined( $serial->{FOUND_DEVICE} ) ? @{ $serial->{FOUND_DEVICE} } : ();
}
sub connection($) {
my $serial = shift;
return $serial->{CONNECTION};
}
sub available_com_ports(;@) {
my $serial = shift;
my $com_port;
my $com_device_name;
my @ports;
my $PortObj;
for ( $com_port = 1 ; $com_port <= $serial->{MAX_PORT} ; $com_port++ ) {
$PortObj = $serial->_get_com_connection($com_port);
if ($PortObj) {
push( @ports, $com_port );
$PortObj->close;
undef $PortObj;
}
undef $PortObj; # Just extra safe measure
}
return @ports;
}
sub scan_ports(;@) {
my $serial = shift;
my $com_port;
my $com_device_name;
my $PortObj;
my $feedback;
my $count_in;
my $send;
my $baud;
my $parm;
my $value;
my $key;
my ( $databits, $parity, $stopbits, $handshake );
my $setting;
my $device;
my $config = $serial->{SEARCH_PARM} = {};
my $parm_found;
my $read_iterations;
my $iterations;
my $chars = 0;
my ( $bytes_read, $data_read );
my $waited;
$serial->_add_scan_log("Scan Ports Request");
$serial->_add_scan_log("==================");
# Parse parameters
while ( $parm = uc shift ) {
$value = shift;
$parm_found = 0;
$key = "BAUD";
if ( $parm eq $key ) {
if ( ref $value eq "ARRAY" ) {
@{ $config->{$key} } = @{$value};
}
elsif ( ref $value eq "" ) {
@{ $config->{$key} } = ($value);
}
else {
croak "ERROR: (scan_ports): $key value must be either a SCALAR or ARRAY REF\n";
}
foreach ( @{ $config->{$key} } ) {
if ( !/^\d+$/ ) {
croak "ERROR: (scan_ports): BAUD rate \$_\" not valid\n";
}
}
$parm_found++;
}
$key = "COM";
if ( $parm eq $key ) {
if ( ref $value eq "ARRAY" ) {
@{ $config->{$key} } = map { s/^COM(\d+)/$1/; $_; } @{$value};
}
elsif ( ref $value eq "" ) {
@{ $config->{$key} } = map { s/^COM(\d+)/$1/; $_; } ($value);
}
else {
croak "ERROR: (scan_ports): $key value must be either a SCALAR or ARRAY REF\n";
}
foreach ( @{ $config->{$key} } ) {
if ( !( /^\d+$/ && $_ > 0 && $_ <= 50 ) ) {
croak "ERROR: (scan_ports): COM port \"$_\" not valid\n";
}
}
$parm_found++;
}
$key = "SETTING";
if ( $parm eq $key ) {
foreach ( ref $value eq "ARRAY" ? @{$value} : ($value) ) {
$value = uc $value;
if (/^([5678])([NEO])([12])([NRX])?$/) {
PortScanner.pm view on Meta::CPAN
}
$key = "TEST_STRING";
if ( $parm eq $key ) {
if ( ref $value eq "" ) {
$config->{$key} = $value;
}
else {
croak "ERROR: (scan_ports): $key value must be a SCALAR\n";
}
$parm_found++;
}
$key = "VALID_REPLY_RE";
if ( $parm eq $key ) {
if ( ref $value eq "" ) {
$config->{$key} = qr/$value/;
}
else {
croak "ERROR: (scan_ports): $key value must be a SCALAR\n";
}
$parm_found++;
}
if ( !$parm_found ) {
croak "ERROR: (scan_ports): Parameter \"$parm\" is not valid for scan port\n";
}
}
if ( !exists( $config->{TEST_STRING} ) || !exists( $config->{VALID_REPLY_RE} ) ) {
croak "ERROR: (scan_ports): TEST_STRING and VALID_REPLY must be provided to scan_ports\n";
}
# Handle Default when certain parms were not provided
if ( !exists( $config->{BAUD} ) ) {
@{ $config->{BAUD} } = (qw/1200 2400 4800 9600 19200 38400 57600 115200/);
}
if ( !exists( $config->{COM} ) ) {
@{ $config->{COM} } = ( 1 .. $serial->{MAX_PORT} );
}
if ( !exists( $config->{SETTING} ) ) {
# Default for setting when not provided
push(
@{ $config->{SETTING} },
{
DATABITS => 8,
PARITY => "none",
STOPBITS => 1,
HANDSHAKE => "none",
SETTING => "8N1"
}
);
}
# Figure the number of read iterations is needed
if ( exists( $config->{MAX_WAIT} ) ) {
$serial->_add_scan_log("(Max Wait set at $config->{MAX_WAIT})");
$read_iterations = int( $config->{MAX_WAIT} / ( $serial->{READ_CONST_TIME} / 1000 ) );
$read_iterations = 1 if ( $read_iterations < 1 );
}
else {
# Must always go though the loop once
$read_iterations = 1;
}
# Begin Scan of Com Ports
PORT:
foreach $com_port ( sort { $a <=> $b } @{ $config->{COM} } ) {
$com_device_name = $serial->_get_com_device_name($com_port);
$serial->_add_scan_log("Scan Port COM${com_port} @ $com_device_name");
# Baud rates are attempted from highest to lowest because some
# might be using a virtual COM via USB and it "looks" nicer to
# see the faster buad rate (virtual USB com ports dont care about baud rates or settings)
BAUD:
foreach $baud ( sort { $b <=> $a } @{ $config->{BAUD} } ) {
$serial->_add_scan_log(" Checking with baudrate of $baud");
SETTING:
foreach $setting ( sort { $b <=> $a } @{ $config->{SETTING} } ) {
$serial->_add_scan_log(" Checking with setting of $setting->{SETTING}");
$PortObj = $serial->_get_com_connection($com_port);
if ($PortObj) {
#$PortObj->user_msg("ON");
if ( !$PortObj->baudrate($baud) ) {
# If *::SerialPort says this baudrate is invalid then go to the next one
# (eg. Dont keep scanning it at other settings)
$serial->_add_scan_log(" Warning: Baud rate of $baud is not valid for this com port - skipping to next one");
next BAUD;
}
$PortObj->databits( $setting->{DATABITS} );
$PortObj->parity( $setting->{PARITY} );
$PortObj->stopbits( $setting->{STOPBITS} );
$PortObj->handshake( $setting->{HANDSHAKE} );
# Just kept this based on *::SerialPort examples
$PortObj->buffers( 4096, 4096 );
if ( $PortObj->write_settings ) {
# Ok, port is available, now is it our device?
$PortObj->write( $config->{TEST_STRING} );
$serial->_add_scan_log(" Sending test string \"$config->{TEST_STRING}\"");
# Due to a bug or something, this locks up
# on Windows sometimes
$PortObj->read_char_time( $serial->{READ_CHAR_TIME} );
$PortObj->read_const_time( $serial->{READ_CONST_TIME} );
$feedback = "";
# Calculated outside loops for performance
$waited = 0;
# Wait a maximum amount of time to get expected output but move on
# if we dont get it in the alloted amount of time. This also protects
# us from a device just spewing data.
for ( $iterations = 1 ; $iterations <= $read_iterations ; $iterations++ ) {
# Read from the port
( $bytes_read, $data_read ) = $PortObj->read(255); # docs say this must be 255 always
$waited += $serial->{READ_CONST_TIME};
if ( $bytes_read > 0 ) {
$feedback .= $data_read;
# This is what makes this loop faster
last if ( $feedback =~ /$config->{VALID_REPLY_RE}/ );
}
}
$feedback =~ s/\015?\012$//;
$serial->_add_scan_log( sprintf( " Received back from device \"%s\" (Waited %.2f secs)", $feedback, $waited / 1000 ) );
if ( $feedback =~ /$config->{VALID_REPLY_RE}/ ) {
# Get a new "device" and store all the properties in it
$device = Hardware::PortScanner::Device->new_device($serial);
$device->com_port("COM${com_port}");
$device->baudrate($baud);
$device->databits( $setting->{DATABITS} );
$device->parity( $setting->{PARITY} );
$device->stopbits( $setting->{STOPBITS} );
$device->handshake( $setting->{HANDSHAKE} );
$device->port_name($com_device_name);
$device->setting( $setting->{SETTING} );
$device->{VALID_REPLY} = $feedback;
$device->{TEST_STRING} = $config->{TEST_STRING};
$device->{MAX_WAIT} = $config->{MAX_WAIT} if ( exists( $config->{MAX_WAIT} ) );
push( @{ $serial->{FOUND_DEVICE} }, $device );
# Since this device was found, skip scanning on this port anymore
$serial->_add_scan_log(" Matched valid reply RE so returning");
last BAUD;
}
}
$PortObj->close;
undef $PortObj;
} # PortObj
else {
$serial->_add_scan_log(" Com Port $com_port appears not to be available - skipping to next port");
next PORT;
}
} # Setting
} # Baud
} # Com Port
}
sub connect_to_device(@) {
my $serial = shift;
( run in 1.340 second using v1.01-cache-2.11-cpan-71847e10f99 )