#!/usr/bin/perl -w

# Program to plot data files loaded from a GR-130 Exploranium.
# This handles all 3 types, spectra, survey, and dose
# It is assumed you set dose for Sieverts and 5 second smoothing,
# and survey for 1 second intervals in the unit itself.
# We assume they are under /yourhome/GR130, since that is where
# our sister program, grgrab puts them.  You can navigate anywhere
# but that's where the ones we know how to use will be.

# To use, just run this and use the file-chooser button to pick a file.
# The rest is automatic and obvious.  You can do it over and over 
# without restarting the program.

# pragmas and modules used by this program
use strict;
use Gtk2 -init; # sets up GUI basics
use Glib qw(TRUE FALSE); # ah, teach it truth and falsity - the apple in eden
use Gtk2::GladeXML; # lets GUI come from a glade file
use Graphics::GnuplotIF qw(GnuplotIF); # gnuplot for plots
use File::HomeDir;
#########################################################

############### globals ################################################
my $gui; # pointer to gui
my $filechooser; # pointer to gui object
my $filepath; # file chosen in gui
my $datadir; # where to look for files from GR-130
my $plot; # gnuplot IF instance

my $rawfile; # bytes from selected file
my %header;  # file header info

my @ploty; # y axis for whatever type we are doing now
my @plotx; # ditto for X scale
my $title;  # plot title
my $ylabel; # the usual suspects
my $xlabel; # ""
my $cosmics;  # number of samples that clipped in spectra

my $debug = 1; # extra messages if this is true

################## subs ################################################
####################
#@@@ - This is stupid, so when copying for a new program read below

# To hook this up, in glade use gtk_main_quit as the handler in the 
# mainwin/GtkWidget/destory-event also needed Gtkobject destroy event 
# and check "after".  Did both, now it works.

sub gtk_main_quit  { Gtk2->main_quit; } # fall out of main event loop
########################################################################
sub creategui()
{# create a local scope
 my $guidata; # packed the xml internally, goes here
 local $/; # which makes this undefined for this sub
 $guidata = <main::DATA>; # which makes this slurp the entire "file"
 $gui = Gtk2::GladeXML->new_from_buffer($guidata); # create gui
 $gui->signal_autoconnect_from_package('main'); # hooks subs to signals 
# not so program-specific you couldn't use it again
}
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#######################################################################
# we're not in Kansas anymore, in this gui this event drives everything
# so this routine might as well be the equivalent of "main" in a normal
# perl program

sub on_file_chooser_file_set
{ # read the file, then call the appropriate plot routine with data
local $/; #make this null for this routine so we slurp entire file
$filepath = $filechooser->get_filename(); # file to open	
print "file chosen: $filepath\n" if $debug;
open (FH, "<$filepath") or die "couldn't open $filepath:$!\n";
$rawfile = <FH>; # slurp whole file	
close FH or die "Couldn't close $filepath:$!\n";
decodedata();	# next step is to decode header and do whatever else	
}
########################################################################
sub setdatadir
{ # deprecated, but the deprecators are hubristically dead wrong.  
# They claim the file chooser is smarter than you, but actually it can't
#even see your bookmarks, or these files right after you upload them to
#the PC, even in "recently used".This saves huge annoyances, since we
# already know where our sister program puts the only files we can use.
 $datadir = File::HomeDir->my_home;
 $datadir .= "/GR130";
 print "datadir:$datadir\n" if $debug;	
 $filechooser->set_current_folder($datadir);	
}
########################################################################
sub plotspectra
{
 print "plotspectra\n" if $debug;
 my $i;	
 
 @ploty = unpack("x51S253",$rawfile); # get unsigned ints 3-255	
 $cosmics = unpack("x557C",$rawfile); # last one is energies that clipped
 # easy part done, theoretically.  Now make X axis correspond to bin energy...	
 my $fudge = 661.7 / $header{CsPeak};
 @plotx =();
 for($i=3; $i<256; $i++)
 {
  push (@plotx, ($i*$fudge)); # create array of X energy values
 }
# print "spectra size:$#spectra, xsize:$#energy\n" if $debug;
#####
 undef $plot; # just in case there already was one
# create plot object
$plot =Graphics::GnuplotIF->new(title => "Gamma Spectrum.  Cosmics:$cosmics",
       style =>"lines", xlabel => 'keV', ylabel => 'counts');
    $plot->gnuplot_cmd ("set grid");    
    $plot->gnuplot_cmd ("set key left top"); 
    $plot->gnuplot_set_plot_titles("counts");
#   $plot->gnuplot_cmd ("set log y");
    $plot->gnuplot_plot_xy(\@plotx, \@ploty);
}
########################################################################
sub plotsurvey
{
# set up for 1 second intervals
 my $x = 1;
 print "plotsurvey\n" if $debug;	
 @ploty = unpack("x47V*",$rawfile);
 pop @ploty; # toss last value - it's a checksum
 @plotx = ();
 foreach (@ploty) { push @plotx, $x++; }
#####
 undef $plot; # just in case there already was one
# create plot object
$plot =Graphics::GnuplotIF->new(title => "Survey",
       style =>"lines", xlabel => 'seconds', ylabel => 'counts');
    $plot->gnuplot_cmd ("set grid");    
    $plot->gnuplot_cmd ("set key left top"); 
    $plot->gnuplot_set_plot_titles("counts");
#   $plot->gnuplot_cmd ("set log y");
    $plot->gnuplot_plot_xy(\@plotx, \@ploty);

}
########################################################################
sub plotdose
{
 #@@@ assumes 5s intervals, and nanoSieverts setup in thee unit	
 print "plotdose\n" if $debug;
 my $x = 5;
 my $total;
 print "plotsurvey\n" if $debug;	
 @ploty = unpack("x47f*",$rawfile);
 pop @ploty; # toss last value - it's a checksum
 @plotx = ();
 foreach (@ploty) 
 { 
  push @plotx, $x;
  $x+=5; 
  $total += $_;
  }
  $total *= $x/3600;
  # now figure out real total from actual doses in ns/hr from
  # how many seconds this was
  $total *= $x/3600;
  
  
#####
 undef $plot; # just in case there already was one
# create plot object
$plot =Graphics::GnuplotIF->new(title => "Dose",
       style =>"lines", xlabel => 'seconds', ylabel => 'dose');
    $plot->gnuplot_cmd ("set grid");    
    $plot->gnuplot_cmd ("set key left top"); 
    $plot->gnuplot_set_plot_titles("Nano-Sieverts/Hr, Total = $total nS");
#   $plot->gnuplot_cmd ("set log y");
    $plot->gnuplot_plot_xy(\@plotx, \@ploty);
 	
}

########################################################################
sub decodedata
{ # figure out what we've got and do the right thing about it
	$header{length} = unpack("x4S", $rawfile); 	
	$header{type} = unpack ("x6a", $rawfile); 
	$header{year} = unpack("x7H2",$rawfile) + 2000;	# not quite y2k bug
	$header{month} = unpack("x8H2",$rawfile);
	$header{day} = unpack("x9H2",$rawfile);
	$header{hour} = unpack("x10H2",$rawfile);
	$header{minute} = unpack("x11H2",$rawfile);
	$header{second} = unpack("x12H2",$rawfile);
	$header{clock_time} = unpack("x14S",$rawfile);
	$header{unit} = unpack("x22a",$rawfile);
	$header{geiger} = unpack("x23V",$rawfile); # total geiger counts
	$header{volt} = unpack("x13c",$rawfile)/10;
	$header{FS} = (unpack("x16c",$rawfile)) ? "3.0 MeV" : "1.5 MeV";
	$header{CsPeak} = unpack("x18S",$rawfile)/10;
# TODO - rest of header for later uses

	if ($header{type} eq "A") { plotspectra(); }
	elsif ($header{type} eq "D") { plotdose(); }
	elsif ($header{type} eq "S") { plotsurvey(); }
	else { die "Unknown header type:$header{type}\n";} 		
}

########################################################################
########################################################################

############################# Main #####################################
creategui();
$filechooser = $gui->get_widget('filechooser');
setdatadir(); # see comment in routine...heh
# Enter the event loop
Gtk2->main; # make events work
# we die when the above exits
# do any cleanup or saving of presets here
#close ($gplot) if ($gplot); # might as well...

__END__  # we've put the glade xml file data here and read it from within - so if you change the glade...change this
<?xml version="1.0"?>
<glade-interface>
  <!-- interface-requires gtk+ 2.16 -->
  <!-- interface-naming-policy project-wide -->
  <widget class="GtkWindow" id="window1">
    <property name="visible">True</property>
    <property name="title" translatable="yes">GR-130 plotter</property>
    <property name="default_width">400</property>
    <property name="default_height">100</property>
    <signal name="destroy" handler="gtk_main_quit" after="yes"/>
    <signal name="destroy_event" handler="gtk_main_quit"/>
    <child>
      <widget class="GtkTable" id="table1">
        <property name="visible">True</property>
        <property name="n_rows">3</property>
        <property name="n_columns">3</property>
        <child>
          <widget class="GtkLabel" id="label1">
            <property name="visible">True</property>
            <property name="label" translatable="yes">File to plot -&gt;</property>
          </widget>
        </child>
        <child>
          <widget class="GtkFileChooserButton" id="filechooser">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="has_focus">True</property>
            <signal name="file-set" handler="on_file_chooser_file_set"/>		
          </widget>
          <packing>
            <property name="left_attach">1</property>
            <property name="right_attach">2</property>
          </packing>
        </child>
        <child>
          <widget class="GtkButton" id="quitbutton">
            <property name="label" translatable="yes">Quit</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <signal name="clicked" handler="gtk_main_quit"/>
          </widget>
          <packing>
            <property name="left_attach">2</property>
            <property name="right_attach">3</property>
            <property name="top_attach">2</property>
            <property name="bottom_attach">3</property>
          </packing>
        </child>
        <child>
          <placeholder/>
        </child>
        <child>
          <placeholder/>
        </child>
        <child>
          <placeholder/>
        </child>
        <child>
          <placeholder/>
        </child>
        <child>
          <placeholder/>
        </child>
        <child>
          <placeholder/>
        </child>
      </widget>
    </child>
  </widget>
</glade-interface>
