#!/usr/bin/perl

# clock
# John Jacobsen, NPX Designs, Inc., jacobsen\@npxdesigns.com
# Started: Wed Jul 28 10:18:35 2004
# show or set clock source for dor driver

use strict;
sub usage { return <<EOF;
Usage: clock [0-7|all] [internal|external]
       Only applicable to DOR Rev. 1...
       Reloads the FPGA(s) if you set external or internal!
Examples:
 % clock
 Card 0: internal
 Card 1: external
 % clock 0
 Card 0: internal
 % clock 0 external
 % clock 0
 Card 0: external
 % clock all internal
 % clock
 Clock 0: internal
 Clock 1: internal
EOF
;
	  }

my $pd = "/proc/driver/domhub";
die "No driver loaded?\n" unless -d $pd;

sub lasterr { my $l = `cat /proc/driver/domhub/lasterr`; chomp $l; return $l; }

my $le = lasterr;
if($le !~ /no error occurred since last query/) {
    print "WARNING: lasterr proc file: $le\n";
}

my @ids;
my @cards = <$pd/card*>;
for(@cards) {
    /card(\d+)/;
    push @ids, $1;
}

sub check_lasterr {
    my $le = lasterr;
    if($le !~ /no error occurred since last query/) {
	die "Driver error: $le\n";
    }
}

sub load_fpga {
    my $card = shift; die unless defined $card;
    my $page = shift; die unless defined $page;
    open (FPGA, ">$pd/card$card/fpga") || die "Can't open $pd/card$card/fpga: $!\n";
    print FPGA "reload $page";
    close FPGA;
}

sub rev { 
    my $card = shift; die unless defined $card;
    my $r = `cat /proc/driver/domhub/card$card/rev`; chomp $r;
    return $r;
}

sub do_clock {
    my $card = shift; die unless defined $card;
    my $state = shift; die unless (($state eq "internal") || ($state eq "external")); 
    my $cs    = "$pd/card$card/clksel";
    system "echo $state > $cs";
    load_fpga($card, 3);
    check_lasterr;
    load_fpga($card, 1);
    check_lasterr;
}

my $arg = shift;
my $act = shift;
if(!defined $arg) {
    for(@ids) {
	print "Card $_: ".`cat $pd/card$_/clksel`;
    }
    exit;
} elsif($arg =~ /^(\d+)$/) {
    my $c = $1;
    my $found = 0;
    for(@ids) {
	$found++ if $_ eq $c;
    }
    if(!$found) {
	print "Card $c not found: clock help for help.\n" ;
	exit -1;
    }
    if(rev($c) == 0) {
	print "Card $c is rev 0... skipping.\n";
	exit;
    }
    my $cs = "$pd/card$c/clksel";
    if(!defined $act) { print "Card $c: ".`cat $cs`; exit; }
    if($act eq "internal") {
	do_clock($c, "internal");
	exit;
    } elsif($act eq "external") {
	do_clock($c, "external");
	exit;
    } else {
	die usage;
    }
} elsif($arg eq "all") {
    for(@ids) {
	my $c = $_;
	if(rev($c) == 0) {
	    print "Card $c is DOR rev. 0... skipping.\n";
	    next;
	}
	my $cs = "$pd/card$c/clksel";
	if(!defined $act) { 
	    print "Card $c: ".`cat $cs`; 
	} elsif($act eq "internal") {
	    do_clock($c, "internal");
	} elsif($act eq "external") {
	    do_clock($c, "external");
	} else {
	    print "Unknown action: $act\n";
	    die usage;
	}
    }
} else {
    die usage;
}

__END__

