#!/usr/bin/perl
###############################################################################
#
# mars_timing - Steven Lerner 2/2005
#               Woods Hole Oceanographic Institution
#
# Description: Menu interface to obc_timing. Also get timing stats and 
#              generate gnuplots.
#
# Usage: mars_timing [-p port] [-c cfg_str] [-d]
#
# History:
#       Date       Who    Description
#       ----       ---    ---------------------------------------------------
#    02/26/2005    SL     Create
#    05/24/2005    SL     Added GPS options
#    08/26/2005    SL     Modified substr offset parsing to work on marsdcs
#                         computer - added $fudge1 $fudge2 (set to 0 for win)
#                         Added nsec option. Modified option 9 time stats/GS
#                         for use on only 1 sail bus at a time.
#############################################################################
# add pointer to old files
use lib '/usr/lib64/perl5/5.8.0'
require "getopts.pl";
require "flush.pl";

($path = "$0") =~ s/\/mars_timing//;
push(@INC,"$path");
require "init_port"; #for serial port initialization

$VERSION = "v1.20050826";

$fudge1 = 1; #For marsdcs computer (linux)
$fudge2 = 2; #For marsdcs computer (linux)

&Getopts('dhtp:c:');
#Setup default arg values if args not specified
#[normally initialized before getopts called, modified for RH9.x]
if (!defined($opt_p)) {$opt_p = "";}
if (!defined($opt_c)) {$opt_c = "9600 N 8 1";}


if ($opt_d) {$DEBUG = 1;}
       else {$DEBUG = 0;}
       
$port_string = "/dev/ttyS0"; #Default


if ($opt_h)
   {print "Mars High Precision Timing - $VERSION\n";
    print "Usage: $0 [-p port] [-c cfg_str] [-h] [-t] [-d]\n";
    print "\twhere: \t -p - serial port (eg; $port_string)\n";
    print "\t\t -c - config string (Default: \"9600 N 8 1\")\n";
    #Note: Possible optional additional cfg params
    #raw ignbrk -opost -onlcr -iexten -echo -echoe -echok -echoctl -echoke crtscts cread
    print "\t\t -h - display this help message\n";
    print "\t\t -t - test only, do not send commands\n";
    print "\t\t -d - debug\n";
    exit;
    }

#If test mode, set verify_only flag
if ($opt_t) {$verify_only = "-v";}

if ($DEBUG) {$debug_opt = "-D3";}

#Set default shore and node clock addresses
$shore_clock = "#CKA";
$node_clock  = "#C01A";

################################################
# Loop forever and display Menu Options
################################################
$nsecs = 10;
$done  = 0;
while (!$done)
   {
TOP_MENU:
    print "\nMars High Precision Timing - $VERSION\n";
    print "    ShoreClock: $shore_clock  NodeClock: $node_clock\n\n";
    print "    x) eXit  a) use ShoreClockAddr  b) use NodeClockAddr  c) use nsec\n";
    print "    1) View Shore Clock Time\n";
    print "    2) Set  Shore Clock Time\n";
    print "    3) View Node Clock Time\n";
    print "    4) Set Output Relay\n";
    print "    5) Get Propagation Delay (Latency)\n";
    print "    6) Set Propagation Delay Offset\n";
    print "    7) Syncronize Node Clock to Shore Clock\n";
    print "    8) Send Global Sync\n";
    print "    9) Get Timing Statistics (and send-out !GS every $nsecs sec)\n";
    print "   10) View node clock P,X,I values\n";
    print "   11) View node clock Latency Offset Value\n";
    print "   12) Set   GPS Sync\n";
    print "   13) UnSet GPS Sync\n";
    print "   14) View  GPS Sync\n";
    print "   15) View GPS String\n";

    print "\nEnter Option Number: ";
    $option = <STDIN>; chomp($option); 

    if ($option eq "x") {$done = 1; next;}
    if ($option eq "a") 
      {#Use SHORE clock address
       print "Use SHORE clock address [eg; #CKA]: ";
       $shore_clock = <STDIN>; chomp($shore_clock); 
       goto TOP_MENU;
       }
    if ($option eq "b") 
      {#Use NODE clock address
       print "Use NODE clock address [eg; #C01A]: ";
       $node_clock = <STDIN>; chomp($node_clock); 
       goto TOP_MENU;
       }
    if ($option eq "c") 
      {#Use nsec 
       print "Use nsec [60]: ";
       $nsecs = <STDIN>; chomp($nsecs); 
       if ($nsecs eq "") {$nsecs = 60;}
       goto TOP_MENU;
       }

    if ($option < 1 || $option > 15)
      {print "\n***Invalid selection [$option]\n\n";
       goto TOP_MENU;
       }

    ###########Process menu items here ##############
    if ($option == 1)
      {#View shore clock time
       $ret = `./obc_timing.exe $verify_only $debug_opt -c$shore_clock -C$shore_clock`;
       print "RET=$ret\n";
       }
    elsif ($option == 2)
      {#Set shore clock time
       print "Enter DateTimeStr [dddd hh:mm:ss]: ";
       $date_time_str = <STDIN>; chomp($date_time_str);
       if (length($date_time_str) != 13)
         {print "***Invalid format, expecting-> dddd hh:mm:ss\n";
          goto TOP_MENU;
          }
       $ret = `./obc_timing.exe $verify_only $debug_opt -S -T\"$date_time_str\" -c$shore_clock`;
       print "RET=$ret\n";
       }
    elsif ($option == 3)
      {#View node clock time
       $ret = `./obc_timing.exe $verify_only $debug_opt  -c$shore_clock -C$node_clock`;
       print "RET=$ret\n";
       }
    elsif ($option == 4)
      {#Set output relay
       $ret = `./obc_timing.exe $verify_only $debug_opt  -S -R -C$node_clock`;
       print "RET=$ret\n";
       }
    elsif ($option == 5)
      {#Get propagation delay (Latency)
       $ret = `./obc_timing.exe $verify_only $debug_opt  -L -c$shore_clock -C$node_clock`;
       print "RET=$ret\n";
       #Parse out microseconds and calculate latency offset
       #Returned format: #CKA?L2\n0002 18:03:15.nnnnnn\n0002 18:03:15.nnnnnn\n:etx
       $microseconds1 = substr($ret,23+$fudge1,6);
       $microseconds2 = substr($ret,45+$fudge2,6);
       #print "[micro1=$microseconds1 micro2=$microseconds2 \nret=$ret]\n";

       $delay = 0x1000; #clock ticks (1/1.2288us) - should do a ?D sail command and get this
       $delay = sprintf("%d",$delay/1.2288 + 10000); #convert to microseconds & add 10ms
       $offset = (($microseconds1 - $microseconds2) - $delay) / 2.0;
       print "OFFSET = $offset\n";
       }
    elsif ($option == 6)
      {#Set propagation delay offset (Latency)
       print "Enter Latency microseconds (0-5000): ";
       $offset = <STDIN>; chomp($offset); $offset = sprintf("%04d",$offset);       
       if ($offset < 0 || $offset > 5000)
         {print "***Offset must be between 0-5000\n";
          goto TOP_MENU;
          }
       $ret = `./obc_timing.exe $verify_only $debug_opt  -S -O$offset -C$node_clock`;
       print "RET=$ret\n";
       }
    elsif ($option == 7)
      {#Syncronize node clock to shore clock
       $ret = `./obc_timing.exe $verify_only $debug_opt  -S -c$shore_clock -C$node_clock`;
       print "RET=$ret\n";
       }
    elsif ($option == 8)
      {#Send global sync
       $ret = `./obc_timing.exe $verify_only $debug_opt  -G -c$shore_clock`;
       print "RET=$ret\n";
       }
    elsif ($option == 9)
      {#First get the offset value actual set at node (to calc jitter)
       $ret = `./obc_timing.exe $verify_only $debug_opt  -O\? -C$node_clock`;
       $offset = substr($ret,8,4);
       print "Node Latency Offset = [$offset]\n";
       #Gather statistics - Loop forever doing GS and ?T/?L1
       open(OUT,">>test_clock_data.dat");
       while (1)
         {#Send global sync
          print "sending global sync\n"; 
          $ret = `./obc_timing.exe $verify_only $debug_opt -G -c$shore_clock`;
          print "waiting $nsecs seconds..."; &flush(STDOUT);
          sleep($nsecs); flush(STDOUT); print "\n";
          #Get times from node clocks and strip-off header and trailer info 
          #    (ie;#CK01A?T= dddd hh:mm:ss...@:etx\n#CKA?L1\ndddd hh:mm:ss.ssssss\n:etx)
          $shore_time = `./obc_timing.exe $verify_only $debug_opt -c$shore_clock -C$shore_clock`;
          $timestamp = gmtimestamp(1);
          $shore_time = substr($shore_time,30+9+$fudge1,20);
          $shore_time_us = substr($shore_time,14,6); #microseconds
        
          $node_time  = `./obc_timing.exe $verify_only $debug_opt -c$shore_clock -C$node_clock`;
          $node_time  = substr($node_time,31+9+$fudge1,20);
          $node_time_us  = substr($node_time,14,6); #microseconds
          $node_jitter = $node_time_us - $shore_time_us - $offset;
          print "$shore_clock=[$shore_time]  $node_clock=[$node_time_us]  jitter=[$node_jitter]\n";

          print OUT "$timestamp $shore_time $node_clock $node_time_us $node_jitter\n";
          &flush(OUT);

###Since sail busA and sail busB are independent (for Mars), can only
###monitor 1 subsea clock at a time - this section commented-out
#          $node_time  = substr($node_time,31+23+$fudge1,6); #only want microseconds
#          $node_clockA = "#C01A";
#          $node_timeA  = `./obc_timing.exe $verify_only $debug_opt -c$shore_clock -C$node_clockA`;
#          $node_timeA  = substr($node_timeA,31+23+$fudge1,6); #only want microseconds
#          $node_clockB = "#C01B";
#          $node_timeB  = `./obc_timing.exe $verify_only $debug_opt -c$shore_clock -C$node_clockB`;
#          $node_timeB  = substr($node_timeB,31+23+$fudge1,6); #only want microseconds

#          print "$shore_clock=[$shore_time]  $node_clockA=[$node_timeA]  $node_clockB=[$node_timeB]\n";

#open(OUT,">>test_clock_data.dat");
#print OUT "$shore_time $node_timeA $node_timeB\n";
#close(OUT);
          #print "waiting $nsecs seconds..."; &flush(STDOUT);
          #sleep($nsecs); flush(STDOUT); print "\n";
          }
       close(OUT);
       }
    elsif ($option == 10)
      {#View node clock P,X,I
       $ret = `./obc_timing.exe $verify_only $debug_opt  -A -C$node_clock`;
       print "RET=$ret\n";
       }
    elsif ($option == 11)
      {#View node clock Latency Offset
       $ret = `./obc_timing.exe $verify_only $debug_opt  -O\? -C$node_clock`;
       print "RET=$ret\n";
       }
    elsif ($option == 12)
      {#Set GPS Sync
       $ret = `./obc_timing.exe $verify_only $debug_opt  -S -s1 -c$shore_clock`;
       print "RET=$ret\n";
       }
    elsif ($option == 13)
      {#Unset GPS Sync
       $ret = `./obc_timing.exe $verify_only $debug_opt  -S -s0 -c$shore_clock`;
       print "RET=$ret\n";
       }
    elsif ($option == 14)
      {#View GPS Sync
       $ret = `./obc_timing.exe $verify_only $debug_opt  -s1 -c$shore_clock`;
       print "RET=$ret\n";
       }
    elsif ($option == 15)
      {#View GPS Sync
       $ret = `./obc_timing.exe $verify_only $debug_opt  -g -c$shore_clock`;
       print "RET=$ret\n";
       }

    }
print "\n"; 

#  **  View ShoreClkTime:  obc_timing -c#CKA                       [#CKA?T #CKA?L1]
#  **  View NodeClkTime:   obc_timing -c#CKA -C#C01A               [#C01A?T #CKA?L1]
#  **  Set ShoreClock Time: 
#  **                      obc_timing -S -T"dddd hh mm ss" -c#CKA  [#CKA!T1234 hh mm ss@]
#  **  Set NodeClk Time from ShoreClk:
#  **                      obc_timing -S -c#CKA -C#C01A[,#C01B]    [#C01A!T#CKA?T ]
#  ** [CAN SET MULTIPLE NODE CLKS #C01A!T#C01B!T#CKA?T]
#  **  Get Latency:        obc_timing -L -c#CKA -C#C01A            [#CKA!EC01A<cr> #CKA?L2]
#  **  Set Latency Offset: obc_timing -S -L -c#CKA -C#C01A         [#CKA!EC01A<cr> #CKA?L2 #C01A!Onnnn]
#  **  Set Latency Offset: obc_timing -S -O0500 -C#C01A            [#C01A!O0500]
#  **  Global Sync:        obc_timing -G -c#CKA [-r]               [#CKA!GS]
#  **  Get Time Error:     obc_timing -E -c#CKA -C#C01A            [#CK01A?T#CKA?L1]

exit;

#
# Subroutines Follow
#
sub gmtimestamp {local($no_gmtlabel) = $_[0];
        local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime;
        # zero fill hour,min,sec and month
        if ($sec < 10) {$sec = "0$sec";}
        if ($min < 10) {$min = "0$min";}
        if ($hour < 10) {$hour = "0$hour";}
        $mon += 1; #from gmtime defined 0-11, make it 1-12
        if ($mon < 10) {$mon = "0$mon";}
        if ($mday < 10) {$mday = "0$mday";}
        #make year 4-digits - Note: Year is years since 1900
        $year += 1900;
        if ($no_gmtlabel)
             {return "$year/$mon/$mday $hour:$min:$sec";}
        else {return "$year/$mon/$mday $hour:$min:$sec GMT";}
}

sub gmtimestamp_file {
        local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime;
        # zero fill hour,min,sec and month
        if ($sec < 10) {$sec = "0$sec";}
        if ($min < 10) {$min = "0$min";}
        if ($hour < 10) {$hour = "0$hour";}
        $mon += 1; #from gmtime defined 0-11, make it 1-12
        if ($mon < 10) {$mon = "0$mon";}
        if ($mday < 10) {$mday = "0$mday";}
        #make year 4-digits - Note: Year is years since 1900
        $year += 1900;
        return "$year$mon$mday";
}


