#!/usr/bin/perl -w

use Device::SerialPort;
use Term::ReadKey;
use Getopt::Long;
use Time::HiRes qw(usleep);

use strict;

my $filename = '';
my $second = '';
my $term = '/dev/ttyUSB0';
my $baud = '115200';
my $verbose;
my $rts = 'rts';
my $command = '';
my $first_delay = 50;
my $second_delay = 100;
my $do_exit;
my $zerolen;

GetOptions ('file=s' => \$filename,
	    'secondfile=s' => \$second,
	    'zerolen' => \$zerolen,
	    'terminal=s' => \$term, 
	    'verbose' => \$verbose, 
	    'u|baud=s' => \$baud,
	    'rts=s' => \$rts,
	    'command=s' => \$command,
	    'a=s' => \$first_delay,
	    'b=s' => \$second_delay,
	    'exit' => \$do_exit,
    ) or die 'bad options';

$| = 1;

if($filename eq '') {
    print "Example usage: mc1322x-load.pl -f foo.bin -t /dev/ttyS0 -b 9600\n";
    print "          or : mc1322x-load.pl -f flasher.bin -s flashme.bin  0x1e000,0x11223344,0x55667788\n";
    print "          or : mc1322x-load.pl -f flasher.bin -z  0x1e000,0x11223344,0x55667788\n";
    print "       -f required: binary file to load\n";
    print "       -s optional: secondary binary file to send\n";
    print "       -z optional: send a zero length file as secondary\n";
    print "       -t, terminal default: /dev/ttyUSB0\n";
    print "       -u, --baud baud rate default: 115200\n";
    print "       -r [none|rts] flow control default: rts\n";
    print "       -c command to run for autoreset: \n";
    print "              e.g. -c 'bbmc -l redbee-econotag -i 0 reset'\n";
    print "       -e exit instead of dropping to terminal display\n";
    print "       -a first  intercharacter delay, passed to usleep\n";
    print "       -b second intercharacter delay, passed to usleep\n";
    print "\n";
    print "anything on the command line is sent\n";
    print "after all of the files.\n\n";
    exit;
}

if (!(-e $filename)) { die "file $filename not found\n"; }
if (($second ne '') && !(-e $second)) { die "secondary file $second not found\n"; }

my $ob = Device::SerialPort->new ($term) or die "Can't start $term\n";
    # next test will die at runtime unless $ob

$ob->baudrate($baud);
$ob->parity('none');
$ob->databits(8);
$ob->stopbits(1);
if($rts eq 'rts') {
    $ob->handshake('rts');
} else {
    $ob->handshake('none');
}
$ob->read_const_time(1000); # 1 second per unfulfilled "read" call
$ob->rts_active(1);

my $s = 0;
my $reset = 0;
my $size = 0;

while(1) { 
    
    my $c; my $count; my $ret = ''; my $test='';
    
    if($s == 1) { print "secondary send...\n"; }
    
    $ob->write(pack('C','0'));

    if(($command ne '') &&
       ($reset eq 0)) {
	$reset++;
	system($command);
    }

    if($s == 1) { 
	$test = 'ready'; 
    } else {
	$test = 'CONNECT';
    }
    
    until($ret =~ /$test$/) {
	($count,$c) = $ob->read(1);
	if ($count == 0) { 
	    print '.';
	    $ob->write(pack('C','0')); 
	    next;
	}
	$ret .= $c;
    }
    print $ret . "\n";
    
    if (-e $filename || (defined($zerolen) && ($s == 1))) {
	
	if(defined($zerolen) && ($s == 1)) {
	    $size = 0;
	} else {
	    $size = -s $filename;
	}

	print ("Size: $size bytes\n");
	$ob->write(pack('V',$size));

	if(($s == 0) ||
	   ((!defined($zerolen)) && ($s == 1))) {
	    open(FILE, $filename) or die($!);
	    print "Sending $filename\n";
	    
	    my $i = 1;
	    while(read(FILE, $c, 1)) {
		$i++;
                usleep($first_delay)  if ( $s == 0 ) && ($first_delay != 0);
                usleep($second_delay) if ( $s == 1 ) && ($second_delay != 0);
		$ob->write($c);
	    }
	}
    }
    
    last if ($s==1);
    if((-e $second) || defined($zerolen)) {
	$s=1; $filename = $second;
    } else {
	last;
    }

} 

print "done sending files.\n";

if(scalar(@ARGV)!=0) {
    print "sending " ;
    print @ARGV;
    print ",\n";

    $ob->write(@ARGV);
    $ob->write(',');
}

if(defined($do_exit)) {
    exit;
}

my $c; my $count;
while(1) {
    ($count, $c) = $ob->read(1);
    print $c if (defined($count) && ($count != 0));
}

$ob -> close or die "Close failed: $!\n";
ReadMode 0;
undef $ob;  # closes port AND frees memory in perl
exit;