#!/usr/bin/perl
# Serial loopback tester
#
#	(C) Copyright (C) 2000
#	    Bill Ryder (bryder@sgi.com)
#
# 	This program is free software; you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation; either version 2 of the License, or
#	(at your option) any later version.
#

# This will check serial port functionality - you need to have a 
# loopback plug connected to the serial port. 
# The one I tested had 2-3, 4-5, 6-20-8-22

use strict;
use Fcntl;

# 
# Note you will probably have to run h2ph
#   cd /usr/include ; h2ph -r -l .

use POSIX qw(:termios_h);
use IO::Handle;
# use Getopt::Std; - Don't like this library

require "getopts.pl";

# Command line options
my ($verbose, $min_count, $max_count, $tty_dev_name);
$verbose = 0;
$min_count = 1;
$max_count = 256;
$tty_dev_name = "/dev/ttyUSB0";

# Used to control serial line discipline et cetera
my ($term, $oterm, $noecho, $echo);

# Files etc
my ($fd_ser);

# Temps
my ($count_read, $count_towrite);
my ($data_read, $data_towrite, $xes, $str_size,  $match_failed);

# Parse command line options
# use strict mandates these definitions 
use vars qw/ $opt_v $opt_s $opt_e $opt_t /;

Getopts('vs:e:t:') || print_usage() ; # man Getopt::Std
$verbose = 1 if $opt_v;
$min_count = $opt_s if $opt_s;
$max_count = $opt_e if $opt_e;
$tty_dev_name = $opt_t if $opt_t;

if ($max_count > 255) {
    print "The test will fail (probably) if > 255 bytes is written\n";
    print " this is because of the simplistic way the data is read\n";
    # If you run with > 255 you will see that the sysread returns less 
    # data then you would expect - but the data is OK - it just doesn't
    # get returned in the read.n
}
if ($verbose) {
    print "Min Count: $min_count, Max Count: $max_count, Device: $tty_dev_name\n";
}


sub print_usage()
{ 
    print "Usage: $0 [-s start bytes] [-e end bytes] [-t ttydevName] -v\n";
    print " EG: $0 -s 1 -e 240 -v -t /dev/ttyUSB0\n";
    exit(-1);
}

# Have to turn off echo to make the loopback work 
sysopen(SER, $tty_dev_name, O_RDWR) || 
       die ("Can't open '$tty_dev_name' - error : $!");

# See perlfaq8 for details on this stuff
$fd_ser = fileno(SER);
$term = POSIX::Termios->new();
$term->getattr($fd_ser) || die("Failed getattr: $!");
$oterm = $term->getlflag() || die("Failed getlflag: $!");

$echo   = ECHO | ECHOK | ICANON;
$noecho = $oterm & ~$echo; 

$term->setlflag($noecho); # Have to have no echo for this to work
$term->setcc(VTIME, 0);
$term->setattr($fd_ser, TCSANOW) || die "Failed setattr: $!";

my $count ; # will be actual byte count
$count = $min_count;

while (1 == 1) # Loop exited at the end of the block (see last if)
{
    # Could make this data more rigorous - ie random
    $xes = 'X' x ($count - 2) ; # The correction is for the start/end bangs
    if ($count > 2) {
	$data_towrite = "!$xes!";
    } elsif ($count == 2) {
	$data_towrite = "!!"; 
    } elsif ($count <= 1) {
	#Zero count still makes one byte
	$data_towrite = "!";
    }
    $match_failed = 0;

    $count_towrite = length($data_towrite);

    $term->setcc(VMIN, $count_towrite); 
    $term->setattr($fd_ser, TCSANOW) || die "Failed setattr: $!";

    syswrite(SER,$data_towrite,$count_towrite) || die("Failed to write: $!");
    $count_read = sysread(SER,$data_read,$count_towrite);

    print "count: $count, bytes read: $count_read\n";

    if ($count_towrite != $count_read) {
	print "Lengths don't match, Wrote: $count_towrite bytes Read: ", length($data_read), " bytes \n";
    }

    if ( $data_towrite eq $data_read) {
	$verbose && print "MATCH OK\n";
    } else { 
	print "ERROR - NON MATCH \n";
	$match_failed = 1;
    }

    ( $verbose || $match_failed ) && print "\tWrote: '$data_towrite'\n";
    ( $verbose || $match_failed ) && print "\t Read: '$data_read'\n";
    $count++;
    last if ( $count > $max_count);

}


