#!/usr/bin/perl
use warnings;
use Getopt::Std;
use Device::SerialPort;

$cmd = $0;
getopts("i:s:d:t:b:hHvc", \%opts);
$prog_name = "Binary cat";
$prog_version = "v0.1";
$prog = $prog_name . " " . $prog_version;
$release_date = "2004-07-28";
$copy = "Copyright (C) Peter Ivanov <ivanovp_at_freemail_dot_hu>, 2004";

#select STDOUT; $| = 0; # make unbuffered

if (length(%opts) == 1 || $opts{h}) {
  usage();
}
if ($opts{v}) {
  print "$prog\n";
  print "Released: $release_date\n";
  exit;
}
if ($opts{c}) {
  copyright();
}
my $infile1 = '';
my $serial_mode = 0;
my $conn_type = "8n1";
my $baud = "38400";
my $div = 16;
my $bighex = 0;
if ($opts{i}) {
    $infile1 = $opts{i};
}
if ($opts{s}) {
    $infile1 = $opts{s};
    $serial_mode = 1;
}
if ($opts{b}) {
    unless ($serial_mode) {
        print "ERROR: Only the serial device has baud rate!\n\n";
        usage();
    }
    $baud = $opts{b};
}
if ($opts{t}) {
    unless ($serial_mode) {
        print "ERROR: Only the serial device has baud rate!\n\n";
        usage();
    }
    $conn_type = $opts{t};
}
if ($opts{d}) {
    $div = $opts{d};
}
if ($opts{H}) {
    $bighex = 1;
}
if (!($infile1)) {
    die "Missing parameter!\n";
}
print "Input file/device: $infile1\n";
print "Division: $div\n";
print "\n";

my $fh;
my ($port, $port2);
if ($serial_mode) {
    my $databits = substr ($conn_type, 0, 1);
    my %parity_str = ("n" => "none", "o" => "odd", "e" => "even");
    my $parity = $parity_str{substr ($conn_type, 1, 1)};
    my $stopbits = substr ($conn_type, 2, 1);
    my $Configuration_File_Name = $ENV{HOME} . "/.serialport";
    
    print "Opening device $infile1... ";
    $port = new Device::SerialPort ($infile1) || die "Can't open $infile1: $!\n";
    print "Ok.\n";
    $port->baudrate ($baud);
    print "Baud: $baud\n";
    $port->databits ($databits);
    print "Data bits: $databits\n";
    $port->parity ($parity);
    print "Parity: $parity\n";
    $port->stopbits ($stopbits);
    print "Stop bit(s): $stopbits\n";
    $port->handshake ("none");
    $port->datatype ("raw");
    $port->save ($Configuration_File_Name) || 
        warn "Can't save $Configuration_File_Name: $!\n";
    #$port->close || warn "$infile1 close failed!\n";
    $port2 = tie (*FH1, 'Device::SerialPort', $Configuration_File_Name) || 
        die "Can't tie: $!\n";
}
else {
    print "Opening $infile1... ";
    
    open (FH1, "<", $infile1) || die "Can't open $infile1.\n";
    binmode (FH1);
    print "Ok.\n";
    $fh = FH1;
}

sub printbuf ($$$$@) 
{
    my ($len, $info, $bighex, $div, @buf) = @_;
    #my ($bighex, $div, @buf) = @_;
    my $bufhex = ''; # buffer in hex format
    my $buffmt = ''; # buffer in preformatted format
    my $buflen = @buf;
    for ($i = 0; $i < $buflen; $i++) {
        my $s = $bighex ? "%02X " : "%02x ";
        $bufhex .= sprintf ($s, ord ($buf[$i]));
        if (ord ($buf[$i]) >= 32 && ord ($buf[$i]) <= 255) {
            $buffmt .= $buf[$i];
        }
        else {
            $buffmt .= ".";
        }
    }
    printf ("%-" . $len . "s | %-" . $div * 3 . "s| %s\n", $info, $bufhex, $buffmt);
    #printf ("%-" . $div * 3 . "s| %s\n", $bufhex, $buffmt);
}

#$fnlen = length (@$infile1);
my $bufsize = $div;
my $pos = 0;
while ($serial_mode || (!$serial_mode && !eof (FH1))) {
    my $pr = 0;
    my $buf1 = ' ' x $bufsize; # little buggy Device::Serial
    my $r1 = read (FH1, $buf1, $bufsize);
    if (!defined ($r1)) {
        die "Can't read! Error: $!\n";
    }
    if ($r1 > 0) {
        $pos += $r1;
        my @b1 = ();
        @b1 = split (//, substr ($buf1, 0, $r1)); # cut off trailing spaces if $r1 < $bufsize
        printbuf (8, sprintf ($bighex ? "%8X" : "%8x", $pos - $r1), $bighex, $div, @b1);
        #printbuf ($bighex, $div, @b1);
    }
}
#print "Closing $infile2...";
close FH1;
#print "Ok.\n";
if ($serial_mode) {
    $port->close || warn "$infile1 close failed!\n";
}
exit 0;


##############################################################################
sub usage
{
    die<<"EOT";
$prog
$copy

This program comes with ABSOLUTELY NO WARRANTY; for details type `$cmd -c'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `$cmd -c' for details.

Usage: $cmd [-i <infile> | -s <serial_device>] [-d <number> -b <baud> -t <connection_type> -H -h -v -c]
Options:
  -i: input file 
  -s: serial device (e.g.: /dev/ttyS0)
  -d: division number (default: 16)
  -H: hex with big alphas
  -b: baud rate (default: 38400)
  -t: connection type (default: 8n1)
  -h: prints help
  -v: prints version
  -c: prints copyright informations
EOT
}

sub copyright
{
    die<<"EOT";
$prog
$copy

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 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

EOT
    exit;
}

