#!/usr/bin/perl -w

# program to attempt to suck up and display 
# spectra from the GR 130

use strict;
use Device::SerialPort;
use Graphics::GnuplotIF;
 
my $key; 
my $value;
my $debug = 1;


my $port; # serial port object
my $bytecount; # how much is in the queue
my $rawport; # raw data from instrument
my $rawcount; # how much?
my @rawbytes; # after splitting raw into bytes

my $plot;  # gnuplotIF object

my %header; # header from GR, parsed
my @energy;   # 'X' bin labeling if I get that far
my @spectra; # from GR, to plot
my $cosmics; # from GR, bin 256 as it were
# there is more than one type of data, more arrays will go here TODO

################################################################################
sub findSpec ()
{ # returns the filepath for the FTDI for GR 130 we find under /dev/serial/by-id
 my $apath;
 
 opendir(DIR,'/dev/serial/by-id') or die "No USB serial devices at all: $!\n";
 while (defined($apath = readdir(DIR)))
 {
  if ($apath =~ m/usb-ftdi_usb_serial_converter_ftDXIAYU-if00-port0/) # match our usb serial?
   {
    $apath = '/dev/serial/by-id/' . $apath; #concatenate
    print "apath:$apath\n" if $debug; # debug
    closedir(DIR); # be nice and clean
    return $apath;
   } 
 }
 die "No GR 130 found - we can't get data if there isn't any device connected!";
}
################################################################################
sub setupSerial
{
	my $status;
	my $portpath = findSpec(); # get path to desired port
     $port = new Device::SerialPort ($portpath, 1) || die "Can't open $portpath: $!\n";
     $port->databits(8);
     $port->baudrate(9600); # GR 130 is 9.6kb?
     $port->parity("none");
     $port->stopbits(1);
     $port->handshake("none");
     $port->datatype('raw');
     $port->stty_icanon(0);
     $port->are_match("\n");                       # possible end strings
     $port->lookclear;                             # empty the buffer
     $port->read_char_time(10);     #  wait for each character - a little
     $port->read_const_time(1000); #  milliseconds per unfulfilled "read" call
     $port->write_settings or undef $port; # die, sort of, if not working
     die "no port at $portpath: $!" unless $port;  # die, really 
     $status = $port->can_status;
     print "port can_status: $status\n" if $debug; # automatically detected
     sleep 1;  # give this time
 # should now have a port open to the device we wanted.    	
}
################################################################################
sub getrawdata
{
 $bytecount = 0;	
  while (0 == $bytecount) # wait for a spectra
  {
   (undef,$bytecount,undef,undef) = $port->status();
   sleep 1;	
   print ".\n" if $debug;
  }
  sleep 1; #make sure we get them all
  (undef,$bytecount,undef,undef) = $port->status();  
  ($rawcount,$rawport) = $port->read($bytecount);
   @rawbytes = split (//,$rawport);
   print "raw bytecount:$rawcount, post-split:$#rawbytes\n" if $debug;  
}
################################################################################
sub dorawheader
{ 
 if ($rawcount > 47)
 { # we have a header (at least)
		
	$header{length} = unpack("x4S", $rawport); 	
	$header{type} = unpack ("x6a", $rawport); 
	$header{year} = unpack("x7H2",$rawport) + 2000;	# not quite y2k bug
	$header{month} = unpack("x8H2",$rawport);
	$header{day} = unpack("x9H2",$rawport);
	$header{hour} = unpack("x10H2",$rawport);
	$header{minute} = unpack("x11H2",$rawport);
	$header{second} = unpack("x12H2",$rawport);
	$header{clock_time} = unpack("x14S",$rawport);
	
	$header{volt} = unpack("x13c",$rawport)/10;
	$header{FS} = (unpack("x16c",$rawport)) ? "3.0 MeV" : "1.5 MeV";
	$header{CsPeak} = unpack("x18S",$rawport)/10;
	$header{doseunit} = unpack("x22a",$rawport);
#TODO - rest of header for later uses
	 	
 } else {die "no header recieved\n";}
 
 # if we get here, print header data if debug
 if ($debug)
 {
  while (($key, $value) = each (%header))
  {
   print "header $key = $value\n";
  }
 }
} 
################################################################################
sub makeplotarrays
{ # assumes we've got data, done header, etc
 die "not a spectrum\n" unless $header{type} eq 'A'; # implies some TODO
 my $i;	
 @spectra = unpack("x51S253",$rawport); # get unsigned ints 3-255	
 $cosmics = unpack("x557C",$rawport);
 # easy part done, theoretically.  Now make X axis correspond to bin energy...	
 my $fudge = 661.7 / $header{CsPeak};
 @energy =();
 
 
 for($i=3; $i<256; $i++)
 {
  push (@energy, ($i*$fudge)); # create array of X energy values
#  print "i=:$i\n";	 
 }
 print "spectra size:$#spectra, xsize:$#energy\n" if $debug;

}
################################################################################
sub makeplot
{


# 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");
#    $cplot->gnuplot_cmd ("set log y");

    $plot->gnuplot_plot_xy(\@energy, \@spectra);
	
}

################################################################################
################################################################################
################################################################################
setupSerial();
print "jello, world, I exist, send me a spectra and I'll plot it!\n";
getrawdata();
dorawheader();  # parse data in header into hash %header
makeplotarrays();
makeplot();
print "hit <CR> to quit\n";
my $dummy = <>; # wait for an eol
print "Bye!\n";
