#! /usr/bin/perl -w

##########################################################
#
# Capture and display data from Standard Data Aq device
#
# (C) 2012 Doug Coulter, GPL v2 license -- share and enjoy,
# but if you improve it, be sure and share it back, to
# clab@swva.net, or www.coultersmithing.com/forums
#
#
# See use section below for any modules you'll need to install first
# Else, run this from a terminal, and look at the runtime errors to see what modules
# you lack - unbuntu sofware center is the easiest way to get them installed.
##########################################################
# It's probably obvious I'm coding this like I was a C programmer
# (because I am), and squishing fancy expressions into single liners
# would just make the inevitable changes this is going to need harder
# to figure out later -- for a C programmer (me).
#
# Anything I thought was dodgy is marked with an @@@ for searching
#
# If you're a perl purist or stylist, sorry 'bout that.  
# TMTOWTDI and, TANSTAAFL for good measure.
# Lots of steal-me code here for beginning perl people
##########################################################
#
# Note, I'm using a goodly number of globals here to avoid tons of typing
# parameters into subroutines.  Most assume you'll call them in the right
# order and they're valid.  This only works for well-disciplined programmers
# and not even for them if things get too big and confusing. It's not stylin',
# don't do this at home.  It does make things faster to run and to write if
# you keep it all in your head well enough. Flame me if you want.  This works.

use strict; # make perl tell me about typos and how dumb I am - built in

# Bring in a pile of library modules, this code is already written and tested by 
# someone else (mostly).  Most of these aren't standard, but have to be gotten from
# CPAN and installed via the standard way for your platform
# you have to have gnuplot, gtk2 (already in linux) installed as well.

use Gtk2 -init; # sets up GUI basics
use Glib qw(TRUE FALSE);
use Gtk2::GladeXML; # lets GUI come from a glade file
use Graphics::GnuplotIF qw(GnuplotIF); # gnuplot for plots

# these are probably already in your perl install
use File::Spec::Functions qw/:ALL/; # changes things like ./ to a real path
use File::Basename; # to get path to program for config files and logs

# the serial interface "requires" different modules for windows and perl, so they're not up here
# but are decided at runtime after perl tells us which opsys we have. We use "require" rather than
# "use" so we only pull in the one needed at runtime.  No system would have both.

#####################################################
################   Globals   ########################
#####################################################
my $gui; # main window
my $ssbut; # start-stop button
my $running = FALSE; # start off stopped...duh
my $makelog;    # boolean value
my $pmakelog;	# ref to checkbox
my $plotc;	# pointer to do counter plot checkbox
my $bcountscl;	# pointer to counter scale checkbox
my $tcountscale; # textbox for scale
my $countscale;	# count scale to use for plot (only)
my $countlabel; # label for plot y axis

my $plotad;	# a/d plot checkbox for a/d plots
my $badscl;	# checkbox for a/d scale
my $tadscale;	# textbox for a/d scale value
my $adscale;	# scale factor for a/d
my $adlabel;	# label for a/d plot y axis

my $logwin;	 # text-edit widget reference
my $logwinbuf;	 # the text buffer reference, special GTK stuff
my $logtext;	 # finally, some actual text itself (text editor windows are complex and a PITA)
my $fonttag;	 # a gtk named tag for setting font

my $filepath;    # hold base path for local files, we'll make up the rest
my $logfilepath; # full path and filename for log file goes in this

my @xaxis;	# for gnu plots
my @C0;		# counter zero plot data
my @C1;		# counter one
my @ad0;	# a/d channel zero
my @ad1;
my @ad2;
my @ad3;	# a/d channel 3
my @ad4;
my @ad5;
my @ad6;
my @ad7;
my $curindex;	# insertion index for next set of data

my $cplot;	# gnuplot instance pointer for counts
my $adplot;	# one for a/d inputs too

my $opsys;	# for serial driver selection
my $port;	# port object reference

# debug stuff 
my $dbgctr = 0;
my $dbgtxt;

#############################################
################   Subroutines   ############
#############################################
# by putting these first, we speed up interpretation
# and avoid having to forward-declare them
#############################################
sub getline()
{ # get a line from std counter
 my $gotit = "";               # start clean
  $gotit = $port->lookfor;      # poll until data ready
#  die "Aborted without match\n" unless (defined $gotit); # @@@ fixme
  my $match = $port->matchclear;# so we dont keep reading the same line over 
 return $gotit;
}
###########################################################
# setup serial port and return false if error, more involved than
# it should have to be, but...that's life.  Even nastier on windows
# once we get that far, count on it.  Probably going to be real hard
# to support later windows than XP or any 64 bit.  Unless you like
# running user programs as Administrator and so on.

sub setupserial()
{
 my $ttyport; # temp for port name to open
 my $portname; # name of port we'll use
 
# first find out what the opsys is
 if ($^O =~ m/linux/i) # special variable tells us opsys
 {
  require Device::SerialPort; # the correct one for linux
  $opsys = 1;  # true for linux
  $ttyport = "usb-Clab_StdDaq_001-if00";   # @@@ for linux only, ID set in PIC
  print ("\nUsing Linux serial driver\n");
 } 
 elsif ($^O =~ m/MSWin32/i)
 {
  require Win32::SerialPort; # the one for windoze
  $opsys = 0; # a big zero for win32
  $ttyport = "COM3"; # @@@ guess for now
  print ("\nUsing Windows serial driver??\n");
  
  ###############ADDED BY TROY (11/14/2011)
  require Win32::TieRegistry;  # this is the library for talking to the registry
  
  #open up the key where we should start looking...
  #NOTE: "Access=>131097" used to be "Access=>KEY_READ()", but the compiler didn't like that
  my $key = new Win32::TieRegistry "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_0461&PID_0033\\",
			{ Access=>131097, Delimiter=>"\\" };
  my $tk;
  foreach $tk ($key->SubKeyNames)
  { #check each immediate subkey, looking for one that contains "Device Parameters"
	my $subKey = $key->Open("$tk\\Device Parameters", { Access=>131097, Delimiter=>"\\" });
	if(defined($subKey))
	{
	  my $PortName = $subKey->GetValue("PortName");
	  if(defined($PortName))         # if a value was populated
	  {
	    print("\nUsing: $PortName"); # let'em know what we found
	    $ttyport = $PortName;        # Assign this port name to the variable we'll use later
	    last;                        #instead of "break"...
	  }
	}
  }
  ###############END TROY ADDITIONS
 }
 else
 {
  die "Unknown opsys: $^O, no driver available."; # we can't do much without a serial driver
 }

# now, init serial port from code defaults or config file
# @@@ this is the linux code, windows will be different?


    my $cfgfile = sprintf("%s.cfg", $ttyport);
    $cfgfile = catfile($filepath,$cfgfile); # with full path to program dir
    
    if($opsys) {$portname = sprintf("/dev/serial/by-id/%s", $ttyport);}
    else {$portname = $ttyport;}  # windows case, com? or something	 

    if ( -e $cfgfile ) {   # cfgfile exists
      if($opsys == 0) {
        $port = Win32::SerialPort->start ($cfgfile) or die "Can't start $cfgfile\n";
      } else {
        $port = Device::SerialPort->start ($cfgfile) or die "Can't start $cfgfile\n";
      }
	} else {   # cfgfile does not exist (e.g. 1st time for a tty device)
	  if($opsys == 0) {
        $port = new Win32::SerialPort ($portname, 1) || die "Can't open $portname: $!\n";
      } else {
        $port = new Device::SerialPort ($portname, 1) || die "Can't open $portname: $!\n";
      }
	}

    # Some of this not needed if config file exists, this is for suspenders (and first times)
    # I put this in the else above, so can reset config by deleting the config on disk
      $port->databits(8);
      $port->baudrate(57600);
      $port->parity("none");
      $port->stopbits(1);
      $port->handshake("none");
      $port->stty_icanon(1);    # this is what gets us on line boundaries
      $port->are_match("\n");                       # possible end strings
      $port->lookclear;                             # empty the buffer
      $port->write_settings || undef $port; # die, sort of, if not working
      $port->save($cfgfile) || warn "Can't save $cfgfile: $!\n"; # save for next time
}
#############################################
sub resetcount()
{ # reset hardware and local data aq variables
 my $done = 0; # done flag for rejecting old or bad lines
 my @fields; # place to split line into
 my @time; # place to look at time field
 my $timeout;
 my $gotit;

 $port->purge_rx; # clean house of any previous junk
 $port->write("!"); #reset clock and counters
# Now, wait for the first good line (complete, and low seconds)

  until ($done)
  {
   my $match = $port->matchclear;# so we dont keep reading the same line over 
   $gotit = "";               # start clean
   $gotit = $port->lookfor;      # poll until data ready
   
   if ($gotit) # did we get a line?
   {
    $timeout++;
#    print ("reset, gotit = $gotit\n"); #@@@ debug
    @fields = split /\s+/,$gotit;
    next if (scalar(@fields) < 13); # lines may grow someday
    # otherwise, check time for valid and not too old
    @time = split (/:/,$fields[0]); # get hh,mm,ss
#   print "time:@time, fields:$fields[0]\n";
#    next if (scalar(@time) < 3); # skip if uninitialized time field
    last if($time[0]*3600 + $time[1]*60 + $time[2] < 3);
    die "timed out waiting for a good line" if ($timeout > 20)
    } # end if gotit
 
    } # end until done
 
 @C0 = (); # clear all the plot data
 @C1 = ();
 @ad0 = ();
 @ad1 = ();
 @ad2 = ();
 @ad3 = ();
 @ad4 = ();
 @ad5 = ();
 @ad6 = ();
 @ad7 = ();
 @xaxis = (); # 
 $curindex = 0;  # stuff them starting at the start again
# clear old plots and other stuff, start new if requested
 $logwinbuf->set_text(''); # wipe any old text from the display window


# experimental, save that first line
 if ($makelog) {print LOG "$gotit\n";} # put the raw line in the logfile if requested
 transcurrent ($gotit); # translate current line for plotting and logging, add in text view


}

#############################################
# Translate current input line to numbers and fill plot arrays

sub transcurrent($) # first time I've used a prototype, required by strict(!)
{ # translate current line into locals
 my $line = shift;
 my @cfields; # place to hold a split line 
 my $h; # for breaking up time
 my $m;
 my $s; 
 my $csec; # current run time in seconds
 my $dtime; # display time HHHHH:MM:SS
# there's probably a more compact way to do the above
 my $idx;
 my $last;
 my @slice; # values to extract a slice

 @cfields = split(/\s+/,$line); # break on whitespace

 # figure out total seconds
 ($h,$m,$s) = split(/:/,$cfields[0]); # break up time and calculate total seconds
# test here for a valid time  and reject line if not
  unless (defined($s)) # most startup data errors don't split the time right
  {
   print ("\nbad line: $line\n");
   return;
  }
 
 $csec = $s + 60 * $m + 3600 * $h;
 $dtime = $cfields[0]; # save for later display

 $last = $#cfields; # last index in whatever we got
 $idx = 2;
 while ($idx <= $#cfields)
 {
  push @slice,$idx;
  $idx += 2; # number fields are on the even numbers
 } 
 @cfields = @cfields[@slice];
 push (@cfields," "); # @@@ loop below needs one past end?

#  fill plot arrays here
#silently replace undef with zero

 defined($cfields[0]) ? $C0[$curindex] = $cfields[0] * $countscale : 0; # c0 data
 defined($cfields[1]) ? $C1[$curindex] = $cfields[1] * $countscale : 0; # c1 data
 
 defined($cfields[2]) ? $ad0[$curindex] = $cfields[2] * $adscale : 0; # a/d data 
 defined($cfields[3]) ? $ad1[$curindex] = $cfields[3] * $adscale : 0; # a/d data
 defined($cfields[4]) ? $ad2[$curindex] = $cfields[4] * $adscale : 0; # a/d data
 defined($cfields[5]) ? $ad3[$curindex] = $cfields[5] * $adscale : 0; # a/d data   
 defined($cfields[6]) ? $ad4[$curindex] = $cfields[6] * $adscale : 0; # a/d data   
 defined($cfields[7]) ? $ad5[$curindex] = $cfields[7] * $adscale : 0; # a/d data   
 defined($cfields[8]) ? $ad6[$curindex] = $cfields[8] * $adscale : 0; # a/d data   
 defined($cfields[9]) ? $ad7[$curindex] = $cfields[9] * $adscale : 0; # a/d data   

 $xaxis[$curindex++] = $csec; # x axis for all plots, point at next location

# Set up a displayable line for the text box
# This almost needs a perl type format setup, but I don't know how yet, so code will get complex.
# Yeah, right justified numbers in fixed length fields ain't easy, is it?
 $line = $dtime; # start with time
 my $cl = length($line); # current line length
 my $dl = 15; # desired length end of first count, was 20 (right justifying here)
 $idx = 0;
 my $el = length($cfields[$idx]); # new element length
 
 while ($idx<$#cfields)
{
 while (($cl + $el) < $dl) 
 { # stuff leading spaces till the right length
  $cfields[$idx] = " " . $cfields[$idx];
  $el = length($cfields[$idx]); # new element length
 }
 $line .= $cfields[$idx]; # add it in
 $cl = length($line);    # new current length
 $idx++;                # point at next entry
 $el = length($cfields[$idx]); # update new element length
 $dl += 8;           # field width
}

 $line = join("",$dtime,@cfields,"\n");

 # add call to text box with edited line
 addtxtline($line);
}
####################
# Make logfile path.  Assumes $filepath is already a valid path, and $logfilepath variable exists
# we'll just make a name out of the local time of day when called...should be unique
# A hassle because we can't use colons for time separator, spaces on some opsys, and slashes to make
# it look as expected, as some opsys would interpret those things as dir separators or invalid name chars
sub makelogfilepath
{
 my $tmp;
 my @time = localtime(); # get array of time data
 $tmp = join('_',$time[4]+1,$time[3],$time[5]+1900,$time[2],$time[1],$time[0]); #join the bits
 $tmp .= '.log'; # add file extension
 $logfilepath = catfile($filepath,$tmp); # put together opsys independent
 #print ("logfilepath:$logfilepath\n"); # debug
}

###########################################################
# Get pathname to program directory for use in config and log files.
# We need this insane dance as the program path in $0 might be ./name
# which is kind of hard to use right.  We want an absolute path where
# the script lives, and this gets it (with two modules needed!).
# It's just lucky they come with perl.
sub getmypath()
{
 my $path = rel2abs($0); # fix up any relative path we got
# print ("\nmunged path is: $path\n"); # debug
 $path = dirname($path); # now get just the dir without progname on it
#print ("\nfinally, path to program is: $path\n"); # debug 
 return $path;
}

####################
# create, open and insert a header line into our logfile
# assumes $logfilepath is valid when called
sub createlogfile
{
 open (LOG, "> $logfilepath") or die "Can't create $logfilepath: $!";
 print LOG "# name:$logfilepath\n"; # human readable help in file
}
####################
# @@@ misnamed now, just closes the file, writing is done as we get the lines in this version
sub writelog 
{ 
# but keep this dead code around to keep the live stuff scared.  Might want to remember
# how to do this trick someday -- it wasn't that easy to work out (arcane)

# get text buffer from edit view and write it to file, then close
  # assumes various variables are good and an open LOG filehandle
# my $start; # text iters for get text
# my $end;
# $start = $logwinbuf->get_start_iter(); # find the start
# $end = $logwinbuf->get_end_iter(); # find the end
# $logtext = $logwinbuf->get_text($start,$end,FALSE); # get the text, no hidden chars
# print LOG $logtext; # do the deed
 close (LOG) or die "Couldn't close $logfilepath: $!"; # all done with this file
}

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

# to hook this up, in glade use gtk_main_quit as the handler in the mainwin/GtkWidget/destory-event
sub gtk_main_quit  { Gtk2->main_quit; } # fall out of main loop and exit

#########################################################################################
# we get here when you click the go/stop button
# to make this work, I had to select the "after" option for the signal in glade
# the assignment of this routine name to the toggled event was done in glade, manually
#########################################################################################
sub on_gostop_toggled
{
 if ($running)
 { # stop, write any log file
  $running = FALSE; # internal boolean flag - stop timer on next call to poll
  $ssbut->set_label('ReStart'); # relabel button
  print ("\nStopping\n"); # debug
  writelog() if $makelog; # this is only checked at start time, so user can't change during a run

# I'm erasing any existing plot when we restart, 
# so you get to hit stop and still study it onscreen until you go again.

 } else # time to start up the world!
 { # setup and start things - get user's desires from GUI controls
  $running = TRUE;
  $ssbut->set_label('Stop');
  $countscale = $bcountscl->get_active ? $tcountscale->get_text : 1;	#scale to use for plot (only)
  $countlabel =  $bcountscl->get_active ? "CPS * $countscale" : 'Counts per second';

  $adscale =  $badscl->get_active ? $tadscale->get_text : 1;		# scale factor for a/d
  $adlabel = $badscl->get_active ? "a/d counts * $adscale (volts)" : '65535 per 5v'; 

#  print ("\ncountscale:$countscale, adscale:$adscale"); # debug

  undef ($cplot); # kill any old plots
  undef ($adplot); # this timing leaves them up as long as possible

  if ($plotc->get_active) 
   {
    $cplot =Graphics::GnuplotIF->new(title => "Counts",
       style =>"linespoints", xlabel => 'Seconds', ylabel => $countlabel);
    $cplot->gnuplot_cmd ("set grid");    
    $cplot->gnuplot_cmd ("set key left top"); 
    $cplot->gnuplot_set_plot_titles("C0-counts","C1-counts");
    $cplot->gnuplot_cmd ("set log y");
   }
  if ($plotad->get_active) 
   {
    $adplot = Graphics::GnuplotIF->new(title => "A/D inputs", raise => FALSE,
       style =>"lines", xlabel => 'Seconds', ylabel => $adlabel);
    $adplot->gnuplot_cmd ("set grid");
    $adplot->gnuplot_cmd ("set key left bottom");
    $adplot->gnuplot_set_plot_titles("a/d 0","a/d 1","a/d 2","a/d 3","a/d 4",
    "a/d 5","a/d 6","a/d 7");
   }
  $makelog = $pmakelog->get_active;
  makelogfilepath(); # create a path and name in current program directory
  createlogfile() if $makelog; # start up a log if requested

#  print ("\nReset and startup. Makelog:$makelog Makeplotopt:$makeplotopt,log plots:$logplots\n"); # debug
  resetcount(); # clear plot buffers, reset hardware, clear serial data
  Glib::Timeout->add(250, \&poll); # start the calls to the poll subroutine
 } # end "if running" else "start case"
} # end on_gostop_toggled

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

# sub to add a line to our text view, then scroll it to the end
# found this trick here: http://www.gtkforums.com/viewtopic.php?t=1307
# and  translated it from C to perl...simpler in perl, actually
sub addtxtline
{ # text edit boxes are a PITA no matter the opsys or GUI toolset, it seems
  # it's not like you could do better -- the full editor is a complex thing
 my $line = shift; # whatever you handed us to insert at end
 my $itere; # a "thing" that marks a place in a textedit buffer
 my $iterb; # same for an iter that points to start
 $itere = $logwinbuf->get_end_iter(); # find the end
 $logwinbuf->insert($itere,$line); # insert at end
 $logwin->scroll_to_iter($itere,0,FALSE,0,0); # scroll to make it visible
 # stuff to get fixed font.  Evidently have to do this for each new line 
 # might only need iters for that one line, but heck, that's harder than this is
 $iterb = $logwinbuf->get_start_iter(); # need to refresh both after buffer mod 
 $itere = $logwinbuf->get_end_iter(); # find the end
 $logwinbuf->apply_tag_by_name ("font", $iterb, $itere); # make all fixed font
}

#################### this one's where the action is during a run
sub poll
{ # we'll have GTK call this on quarter seconds to look for a line of input, 
  # do stuff about that, or return if nothing to do
 return FALSE unless $running; # this also stops the timer hits
# try to get a line from serial port in real thing here
 my $dataline = getline(); # attempt to get a line from hardware port
 unless ($dataline eq "")
 {
  if ($makelog) {print LOG "$dataline\n";} # put the raw line in the logfile if requested
  transcurrent ($dataline); # translate current line for plotting and logging, add in text view
  if ($cplot) {$cplot->gnuplot_plot_xy( \@xaxis, \@C0, \@C1);} # rewrite plot
  if ($adplot) {$adplot->gnuplot_plot_xy(\@xaxis,\@ad0,\@ad1,\@ad2,\@ad3,\@ad4,\@ad5,\@ad6,\@ad7);} # rewrite plot
 }
 return TRUE; # keep timer running
}
#######################################################################################
################  Main program   ######################################################
#######################################################################################
#print ("\nprogram running\n"); # debug
$filepath = getmypath(); # find out where we are despite opsys munging - base dir for all other files
#print "path:$filepath\n"; # debug

# use this once you've put the glade XML in here after _END_
{ # create block so I can diddle record terminator without affecting the rest
 local $/; # remove normal record terminator
 my $guidata = <main::DATA>; # slurp the glade XML at EOF into a variable
 $gui = Gtk2::GladeXML->new_from_buffer($guidata); # and here it is, cool.
}  # end of block restores record separator to whatever it was

# Saved the old code for later... the above is noticeably quicker to come up. 

# use this while editing the glade file, then stuff it in the file after _END_ 
# and use the other constructor
# catfile uses right type of dir separators for whatever opsys
#$gui = Gtk2::GladeXML->new(catfile($filepath,'sdaq.glade')); 

$ssbut = $gui->get_widget('gostop'); # pointer to start button?
$pmakelog = $gui->get_widget('logfileb');
#$pmakelog->set_active(TRUE);

$plotc = $gui->get_widget('plotcounts');
$plotc->set_active(TRUE);
$bcountscl = $gui->get_widget('checkcountscale'); # pointer to checkbox for count scaling
$bcountscl->set_active(TRUE);
$tcountscale = $gui->get_widget('countscale'); # text box
$countscale = $tcountscale->get_text;	# count scale to use for plot (only)

$plotad = $gui->get_widget('plotad');  # plot a/d?
$plotad->set_active(TRUE);
$badscl = $gui->get_widget('checkscalead');	# checkbox for a/d scale
$badscl->set_active(TRUE);
$tadscale = $gui->get_widget('adscale');	# textbox for a/d scale value
$adscale = $tadscale->get_text;		# scale factor for a/d

$logwin = $gui->get_widget('logwin'); # pointer to text display window
$logwinbuf = $logwin->get_buffer(); # later use $logwinbuf->set_text($some_text);
$logwinbuf->create_tag("font",'font'=>'monospace'); # used to set font on text edit window
$gui->signal_autoconnect_from_package('main'); # hooks subs to signals if things are named right

setupserial();	# set up the serial port (fails if USB and not plugged in on linux)
# Enter the event loop
Gtk2->main;

# any cleanup goes here after user hits quit on main window

__END__  # we've put the glade xml file data here and read it from within - if you change the glade...
<?xml version="1.0"?>
<glade-interface>
  <!-- interface-requires gtk+ 2.16 -->
  <!-- interface-naming-policy project-wide -->
  <widget class="GtkWindow" id="mainwin">
    <property name="visible">True</property>
    <property name="tooltip" translatable="yes">Standard data aquisition</property>
    <property name="title" translatable="yes">Standard Data Aquisition</property>
    <property name="default_width">512</property>
    <property name="default_height">768</property>
    <signal name="destroy" handler="gtk_main_quit"/>
    <signal name="destroy_event" handler="gtk_main_quit"/>
    <child>
      <widget class="GtkVPaned" id="vpaned1">
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <child>
          <widget class="GtkLabel" id="label1">
            <property name="visible">True</property>
            <property name="xalign">0</property>
            <property name="label" translatable="yes">     Parameters                     Runtime              C0            C1         AD0         AD1	     AD2         AD3         AD4          AD5         AD6          AD7        </property>
          </widget>
          <packing>
            <property name="resize">False</property>
            <property name="shrink">True</property>
          </packing>
        </child>
        <child>
          <widget class="GtkHPaned" id="hpaned1">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <child>
              <widget class="GtkVButtonBox" id="vbuttonbox1">
                <property name="visible">True</property>
                <child>
                  <widget class="GtkCheckButton" id="logfileb">
                    <property name="label" translatable="yes">Write Log File?</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">False</property>
                    <property name="tooltip" translatable="yes">Write a log file of this run</property>
                    <property name="xalign">0.44999998807907104</property>
                    <property name="draw_indicator">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">0</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkHSeparator" id="hseparator1">
                    <property name="visible">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">1</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkLabel" id="label2">
                    <property name="visible">True</property>
                    <property name="tooltip" translatable="yes">Define what to plot</property>
                    <property name="label" translatable="yes">Plot Selections</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">2</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkCheckButton" id="plotcounts">
                    <property name="label" translatable="yes">Plot counters?</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">False</property>
                    <property name="tooltip" translatable="yes">Make plot of counts?</property>
                    <property name="draw_indicator">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">3</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkCheckButton" id="checkcountscale">
                    <property name="label" translatable="yes">Scale counts?</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">False</property>
                    <property name="tooltip" translatable="yes">Apply scale factor?</property>
                    <property name="draw_indicator">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">4</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkEntry" id="countscale">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="tooltip" translatable="yes">Scale factor</property>
                    <property name="invisible_char">&#x25CF;</property>
                    <property name="text" translatable="yes">60</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">5</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkHSeparator" id="hseparator16">
                    <property name="visible">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">6</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkCheckButton" id="plotad">
                    <property name="label" translatable="yes">Plot a/d?</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">False</property>
                    <property name="tooltip" translatable="yes">Plot a/d data?</property>
                    <property name="draw_indicator">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">7</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkCheckButton" id="checkscalead">
                    <property name="label" translatable="yes">Scale a/d?</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">False</property>
                    <property name="tooltip" translatable="yes">Apply scale to a/d?</property>
                    <property name="yalign">0.47999998927116394</property>
                    <property name="draw_indicator">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">8</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkHSeparator" id="hseparator4">
                    <property name="visible">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">9</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkEntry" id="adscale">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="tooltip" translatable="yes">a/d scale factor</property>
                    <property name="invisible_char">&#x25CF;</property>
                    <property name="text" translatable="yes">0.000076295</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">10</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkHSeparator" id="hseparator6">
                    <property name="visible">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">11</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkHSeparator" id="hseparator7">
                    <property name="visible">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">12</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkHSeparator" id="hseparator8">
                    <property name="visible">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">13</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkHSeparator" id="hseparator9">
                    <property name="visible">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">14</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkHSeparator" id="hseparator10">
                    <property name="visible">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">15</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkHSeparator" id="hseparator11">
                    <property name="visible">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">16</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkHSeparator" id="hseparator12">
                    <property name="visible">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">17</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkHSeparator" id="hseparator13">
                    <property name="visible">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">18</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkHSeparator" id="hseparator14">
                    <property name="visible">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">19</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkHSeparator" id="hseparator15">
                    <property name="visible">True</property>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">20</property>
                  </packing>
                </child>
                <child>
                  <widget class="GtkToggleButton" id="gostop">
                    <property name="label" translatable="yes">Go</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="tooltip" translatable="yes">Go or stop</property>
                    <property name="draw_indicator">True</property>
                    <signal name="toggled" handler="on_gostop_toggled" after="yes"/>
                  </widget>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">21</property>
                  </packing>
                </child>
              </widget>
              <packing>
                <property name="resize">False</property>
                <property name="shrink">True</property>
              </packing>
            </child>
            <child>
              <widget class="GtkScrolledWindow" id="txtscroll">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="hscrollbar_policy">automatic</property>
                <child>
                  <widget class="GtkTextView" id="logwin">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="editable">False</property>
                    <property name="left_margin">10</property>
                    <property name="accepts_tab">False</property>
                  </widget>
                </child>
              </widget>
              <packing>
                <property name="resize">True</property>
                <property name="shrink">True</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="resize">True</property>
            <property name="shrink">True</property>
          </packing>
        </child>
      </widget>
    </child>
  </widget>
</glade-interface>
