]> jspc29.x-matter.uni-frankfurt.de Git - daqtools.git/commitdiff
added Tactical monitor from Hades to daqtools
authorJan Michel <j.michel@gsi.de>
Thu, 10 Jul 2014 18:32:47 +0000 (20:32 +0200)
committerJan Michel <j.michel@gsi.de>
Thu, 10 Jul 2014 18:32:47 +0000 (20:32 +0200)
18 files changed:
.gitignore
dmon/code/Dmon.pm [new file with mode: 0644]
dmon/code/get.pl [new file with mode: 0755]
dmon/code/getpic.pl [new file with mode: 0755]
dmon/code/index.pl [new file with mode: 0755]
dmon/code/indexstyles.css [new file with mode: 0644]
dmon/code/monitor.pl [new file with mode: 0755]
dmon/code/styles.css [new file with mode: 0644]
dmon/example_config.pl [new file with mode: 0644]
dmon/scripts/dmon_numfee.pl [new file with mode: 0755]
dmon/scripts/dmon_qa.pl [new file with mode: 0755]
dmon/scripts/dmon_temperature.pl [new file with mode: 0755]
dmon/scripts/dmon_time.pl [new file with mode: 0755]
dmon/scripts/dmon_trgrate.pl [new file with mode: 0755]
dmon/start.pl [new file with mode: 0755]
dmon/stop.pl [new file with mode: 0755]
tools/HPlot.pm [new file with mode: 0755]
web/htdocs/dmon [new symlink]

index e638d20516bbf75ddd9546c814084fdb384f7e27..86f9099cfe101abbcba65db188f4c2933ff6e432 100644 (file)
@@ -4,3 +4,4 @@ web/htdocs/monitor
 *log
 .kateproject.d
 *swp
+logs
diff --git a/dmon/code/Dmon.pm b/dmon/code/Dmon.pm
new file mode 100644 (file)
index 0000000..1b69ba7
--- /dev/null
@@ -0,0 +1,255 @@
+package Dmon;
+use POSIX qw/floor ceil strftime/;
+use Data::Dumper;
+use warnings;
+use strict;
+
+
+
+print STDERR "Script started at ".strftime("%d.%m.%y %H:%M:%S", localtime()).".\n";
+
+
+
+###############################################################################
+#  Some default settings
+###############################################################################
+
+use constant DMONDIR => "/dev/shm/dmon/";
+our $AcceleratorCycle = 7;
+our $CTSAddress = 0x8000;
+
+
+
+
+
+###############################################################################
+#  Make Title & Footer
+###############################################################################
+sub MakeTitle {
+  my ($width,$height,$title,$time,$error) = @_;
+  my $str;
+  $time = 1 unless defined $time;
+  $str  = "<div class=\"width$width height$height\">\n";
+  if ($time) {
+    $str .= "<div class=\"timestamp\">".strftime("%H:%M:%S", localtime())."</div>\n";
+  }
+  if (defined $error && $error ne "") {
+    $str .= "<div class=\"errorstamp\">$error</div>\n";
+  }
+  $str .= "<h3 id='title'>$title</h3>";
+  return $str;
+}
+
+sub MakeFooter {
+  my $str;
+  $str = "</div>\n";
+  return $str;
+}
+
+sub AddStyle {
+  return "";
+}
+
+
+############################################
+#  Write to File
+############################################
+sub WriteFile {
+  my ($name,$str) = @_;
+  open FH,"> ".Dmon::DMONDIR."/$name.htt";
+  print FH $str;
+  close FH;
+}
+
+
+###############################################################################
+# Voice Synthesis
+###############################################################################
+my $speaklog;
+sub Speak {
+  my ($id,$str) = @_;
+#   print "$id $str $speaklog->{$id}\n";
+  if (!defined $speaklog->{$id} || $speaklog->{$id} < time()-120) {
+#     my $cmd = "ssh hades30 'espeak -ven-male2 -s 120 -g 1 \"$str\" ' 2>/dev/null";
+    my $fh;
+    open($fh, ">>",Dmon::DMONDIR."/speaklog");
+    $fh->autoflush(1);
+    print $fh $str."\n";
+    $speaklog->{$id} = time();
+    close($fh);
+    }
+  }
+
+###############################################################################
+#  Calculate Colors
+###############################################################################
+sub findcolor {
+  my ($v,$min,$max,$lg) = @_;
+  my ($r,$g,$b);
+  $v = 0 unless defined $v;
+  $v = log($v) if $v && $lg;
+  $min = log($min) if $min && $lg;
+  $max = log($max) if $max && $lg;
+  $max  = 1 unless $max;
+
+  my $step = (($max-$min)/655);
+
+
+  if ($v == 0) {
+    $r = 220;
+    $g = 220;
+    $b = 220;
+  } else {
+    $v -= $min;
+    $v  = $v/$step if $step;
+    if ($v<156) {
+      $r = 0;
+      $g = $v+100;
+      $b = 0;
+    } elsif ($v<412) {
+      $v -= 156;
+      $r = $v;
+      $g = 255;
+      $b = 0;
+    } else {
+      $v -= 412;
+      $r = 255;
+      $g = 255-$v;
+      $b = 0;
+    }
+  }
+
+  my $ret = sprintf("#%02x%02x%02x",$r%256,$g%256,$b%256);
+
+  return $ret;
+}
+
+
+###############################################################################
+#  Error Levels
+###############################################################################
+use constant {
+  NOSTATE => -10,
+  SCRIPTERROR => -1,
+  NA => 0,
+  OK => 10,
+  NOTE => 20,
+  NOTE_2 => 22,
+  WARN => 40,
+  WARN_2 => 42,
+  ERROR => 70,
+  ERROR_2 => 72,
+  LETHAL => 100,
+  FATAL => 100
+};
+
+###############################################################################
+#  Functions
+###############################################################################
+
+
+############################################
+# Opens QA Logfile and gives back a filehandle
+sub OpenQAFile {
+  my $fh;
+  open($fh, ">>",Dmon::DMONDIR."/qalog");
+  $fh->autoflush(1);
+  return $fh;
+}
+
+
+
+############################################
+# Writes an entry to the QA file. Arguments:
+# $fh        file handle of logfile
+# $cat       category of entry
+# $entry     name of entry
+# $ttl       time the entry is valid (in seconds)
+# $status    Status, one of the constants defined above
+# $title     First line of monitor entry
+# $value     Second line of monitor entry
+# $longtext  Long description text (PopUp)
+sub WriteQALog {
+  my ($fh, $entry, $ttl, $status, $title, $value, $longtext,$link) = @_;
+  my $tmp = time()."\t$entry\t$ttl\t$status\t$title\t$value\t$longtext\t$link\n";
+
+  if ($fh == 0) {
+    $fh = OpenQAfile();
+    print $fh $tmp;
+    close $fh;
+    }
+  else {
+    print $fh $tmp;
+    }
+
+}
+
+############################################
+# Returns the appropriate status flag (simplified). Arguments:
+# $mode     how to determine status, supported: "below","above"
+# $val      the value
+# @limits   Array with limits
+sub GetQAState {
+  my ($mode, $val, @limits) = @_;
+  my ($ok, $warn, $err) = @limits;
+  if (!defined($val)) {
+    return NA;
+  }
+  if ($val eq "err") {   return SCRIPTERROR; }
+  if ($_[0] eq 'below') {
+    if ($val <= $ok) {   return OK; }
+    if ($val <= $warn) { return WARN;}
+    if ($val <= $err) {  return ERROR; }
+    if ($val >  $err) {  return FATAL; }
+  } elsif ($_[0] eq 'above') {
+    if ($val >= $ok) {   return OK;}
+    if ($val >= $warn) { return WARN;}
+    if ($val >= $err) {  return ERROR;}
+    if ($val <  $err) {  return FATAL;}
+  } elsif ($_[0] eq 'inside') {
+    if (abs($val) <= $ok) {   return OK;}
+    if (abs($val) <= $warn) { return WARN;}
+    if (abs($val) <= $err) {  return ERROR;}
+                              return FATAL;
+  }
+  return SCRIPTERROR;
+}
+
+############################################
+#Returns a string matching the given severity level
+sub LevelName {
+  my ($level) = @_;
+  if ($level == SCRIPTERROR) { return "Script Error";}
+  if ($level == NA) {          return "Not available";}
+  if ($level < NOTE ) {        return "OK";}
+  if ($level < WARN ) {        return "Note";}
+  if ($level < ERROR ) {       return "Warning";}
+  if ($level < FATAL ) {       return "Error"; }
+                               return "Severe Error";
+  }
+
+############################################
+# Tries to nicely format an integer
+sub SciNotation {
+  my $v = shift;
+  return "undef" if (!defined $v);
+  return "0" if $v == 0;
+#   print $v."\n";
+  if(abs($v) >= 1) {
+    return  sprintf("%i", $v) if (abs($v) < 1000) ;
+    return  sprintf("%.1fk", $v / 1000.) if (abs($v) < 20000) ;
+    return  sprintf("%ik", $v / 1000.) if (abs($v) < 1E6) ;
+    return  sprintf("%.1fM", $v / 1000000.) if (abs($v) < 20E6) ;
+    return  sprintf("%iM", $v / 1000000.) if (abs($v) < 1E9) ;
+    return  sprintf("%i",$v);
+    }
+  else {
+    return sprintf("%in", $v*1E9) if (abs($v) < 1E-6) ;
+    return sprintf("%iu", $v*1E6) if (abs($v) < 1E-3) ;
+    return sprintf("%.1fm", $v*1E3);
+    }
+}
+
+
+1;
+__END__
diff --git a/dmon/code/get.pl b/dmon/code/get.pl
new file mode 100755 (executable)
index 0000000..c728aa7
--- /dev/null
@@ -0,0 +1,79 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Data::Dumper;
+use MIME::Base64;
+my $PATH  = "";
+if ($ENV{'SERVER_SOFTWARE'} =~ /HTTPi/i) {
+  print "HTTP/1.0 200 OK\n";
+  print "Expires: Thu, 01 Dec 1994 16:00:00 GMT\r\n";
+  print "Content-type: text/html\r\n\r\n";
+  $PATH = "htdocs/dmon/";
+  }
+else {
+  print "Expires: Thu, 01 Dec 1994 16:00:00 GMT\r\n";
+  print "Content-type: text/html\n\n";
+  }
+
+my @args = split('-',$ENV{'QUERY_STRING'});
+
+sub addpng {
+  my ($file) = @_;
+  my $out = "data:image/png;base64,";
+  open (my $fh, "<$PATH$file");
+  
+  local $/;
+  my $bin = <$fh>;
+  $fh->close();
+  $/='\n';
+  $out .= encode_base64($bin);
+  chomp $out;
+  return $out;
+  }
+
+sub addfile {
+       my ($file,$strip) = @_;
+       my $MYF;
+       $strip = 0 unless defined $strip;
+       my $str = "";
+       open ($MYF, "<$file") or return "";
+       while (<$MYF>){
+#        print $_;
+               if ($_ =~ m%ADDFILE\s([/\w]*).svg%) {
+           $str .= addfile("$PATH$1.svg",1);
+                       }
+               elsif  ($_ =~ m!^(.*)\%ADDPNG\s+(.+)\%(.*)$!) {
+      $str .= $1;
+      $str .= addpng($2);
+      $str .= $3;
+      }
+               else {
+                       $_ =~ s/\t*/ /;
+                 if($_ =~ m/^$/) {next;}
+                 if($strip==1) {
+                   $_ =~ s/<svg/<svg preserveAspectRatio="XMidYMid" /;
+                   if($_ =~ m/<\?/) {next;}
+                   if($_ =~ m/<!/) {next;}
+                   if($_ =~ m/.dtd/) {next;}
+                               }
+#                      my $r = int(rand(1000));
+#                      $_ =~ s/(getpic.cgi\?[^"]+)"/$1-$r"/;
+                       $str .= $_;
+                       }
+               }
+       return $str;
+      }
+
+
+
+my $out;
+       $out .= addfile($PATH."note.htt");
+       foreach my $arg (@args) {
+               if ($arg =~ m/(\w+)/) {
+#                      $out .= $arg;
+                       $out .= addfile($PATH."$1.htt");
+                       }
+               }
+                       
+print $out;
+               
\ No newline at end of file
diff --git a/dmon/code/getpic.pl b/dmon/code/getpic.pl
new file mode 100755 (executable)
index 0000000..913e032
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Data::Dumper;
+use File::Copy;
+my @args = split('-',$ENV{'QUERY_STRING'});
+
+unless($args[0] =~ m/\w+/) {exit;}
+if($args[0] =~ m/\./) {exit;}
+
+
+
+print "Cache-Control: no-cache, must-revalidate, max-age=1\r\n";
+print "Expires: Thu, 01 Dec 1994 16:00:00 GMT\r\n";
+print "Content-type: image/png\r\n\r\n";
+
+system ("cat /dev/shm/files/".$args[0].".png");
+                       
+               
diff --git a/dmon/code/index.pl b/dmon/code/index.pl
new file mode 100755 (executable)
index 0000000..dab0eb2
--- /dev/null
@@ -0,0 +1,77 @@
+#!/usr/bin/perl -w
+use CGI::Carp qw(fatalsToBrowser);
+
+my $PATH = "";
+if ($ENV{'SERVER_SOFTWARE'} =~ /HTTPi/i) {
+  print "HTTP/1.0 200 OK\n";
+  print "Content-type: text/html\r\n\r\n";
+  $PATH = "htdocs/dmon/";
+  }
+else {
+  print "Content-type: text/html\n\n";
+  }
+
+
+
+print qq$<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>Monitoring Main Control Interface</title>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<link href="code/indexstyles.css" rel="stylesheet" type="text/css"/>
+</head>
+<body class="index" style="position:relative;background:#d8e8f8;width:750px;margin:auto;padding:120px 0 40px 0">
+<script type="text/javascript">
+function openwin(url) {
+       win = window.open(url,"window1","width=600,height=400,scrollbars=no,status=no,location=no,menubar=no,resizable=no,titlebar=no,toolbar=no");
+       win.focus();
+       }
+</script>
+<div style="position:fixed;left:0;top:0;width:100%;height:40px;background:#d8e8f8;box-shadow:none;"></div>
+<h1 style="position:fixed;top:5px;left:0px;width:100%;display:block;text-align:center;margin:26px 0 0px 0">DAQ Monitoring</h1>
+
+
+
+
+<div class="linkbox" style="width:730px;"><h4>Main</h4><ul>
+<li style="width:600px;"><a href="code/monitor.pl?1-window-QA" style="color:#d33">Tactical Overview (the central screen)</a></li>
+</ul></div>
+
+
+
+$;
+
+
+print "<h3 style=\"clear:both;padding-top:30px;\">All available options</h3><ul class=\"optionlist\">\n";
+my @o = qx(ls -1 $PATH*.htt);
+foreach my $a (@o) {
+  if ($a =~ m%$PATH(\w+).htt%) {
+    print "<li><a href=\"code/monitor.pl?2-window-$1\">$1</a></li>\n";</li>
+               }
+       }
+print "</ul><br>\n";
+
+
+
+#<h3 style="padding-top:30px;clear:both">Help</h3>
+#To select the information you want to have, specify any number of the options listed below, separated with '-' after the \"monitor.cgi?\".<p/>
+#<ul><li>The first option for monitor.cgi may be a number specifying the update rate in seconds.</li>
+#<li>The first or second option may be \"window\" to open the information in a pop-up with no toolbars and proper sizes. Note that only the first information box is used to determine the size - i.e. if there are two boxes to be shown, you  have to resize the window by hand. One remark: to work properly, you have to set all dom.disable_window_open* options in about:config to false.</li>
+#<li>Everything is tested in the latest version (5 and above, not 2 or 3!) of the Firefox browser - there will be no support for any other kind of html-viewer.</li>
+#</ul>
+#<h5>Hints</h5>
+#<ul><li>Window background will turn red if no update is possible. </li>
+#<li>If you see a message "Server Error", press F5. </li>
+#<li>If you want to stop updating, press Esc. </li>
+#<li>To restart updating, press F5.</li>
+#<li>Zoom in and out with Ctrl++ and Ctrl+-, normal zoom with Ctrl+0.</li>
+#</ul>
+#<h5>Examples</h5>
+#<ul><li><a href="monitor.cgi?logfile-busy">monitor.cgi?logfile-busy</a></li>
+#<li><a href="monitor.cgi?2-PTrates-busy">monitor.cgi?PTrates-busy</a></li>
+#<li><a href="monitor.cgi?10-window-MDCRates">monitor.cgi?10-MDCRates</a></li>
+#</ul>
+print qq$
+</body>
+</html>
+$;
diff --git a/dmon/code/indexstyles.css b/dmon/code/indexstyles.css
new file mode 100644 (file)
index 0000000..32e5f02
--- /dev/null
@@ -0,0 +1,178 @@
+
+
+body.index {
+       overflow:auto;
+       font-size:13px;
+  font-family:sans-serif;
+       background: right bottom url('background.png') no-repeat fixed #def;
+       line-height:150%;
+
+       }
+
+body.index h1 {
+       color:white;
+       font-size:25px;
+       background:#346;
+       margin:-8px;
+       width:470px;
+  box-shadow:0px 0px 4px 4px #346;/*, inset 3px 3px 3px 3px #eee, inset -3px -3px 3px 3px #eee;*/
+       padding:20px 10px 15px 10px;
+       }
+
+body.index h2 {
+       color:white;
+       font-size:20px; 
+       background:#346;
+       margin:8px -8px 10px -8px;
+       padding:0 10px 10px 10px;
+  box-shadow:0px 0px 4px 4px #346;/*, inset 3px 3px 3px 3px #eee, inset -3px -3px 3px 3px #eee;*/
+  width:470px;
+
+}
+       
+body.index h3 {
+       font-weight:bold;
+       font-size:18px;
+       display:block;
+       margin:30px 0 20px 0;
+       }
+
+body.index h4 {
+       clear:both;
+       font-weight:bold;
+       font-size:16px;
+       margin:30px 0 20px 0;
+       }
+
+       
+       
+body.index div h4 {
+/*     text-align:center; */
+       clear:both;
+       font-weight:bold;
+       font-size:15px;
+       margin:0px 0 0 0;
+       }
+       
+body.index div ul{
+       margin:0 20px 0 20px;
+       width:300px;
+       margin-bottom:0px;
+       padding-left:13px;
+       }
+
+body.index ul{
+       margin:0 20px 0 20px;
+       margin-bottom:0px;
+       padding-left:13px;
+       }
+
+
+body.index li {
+       list-style-type: square;
+       }
+       
+
+body>div, .logos {
+  float:left;
+  margin: 0px 8px 12px 8px;
+       padding: 0 0 0 0 ;
+
+  text-align:center;
+  box-shadow:0px 0px 4px 4px #eef8ff;/*, inset 3px 3px 3px 3px #eee, inset -3px -3px 3px 3px #eee;*/
+  border-radius: 5px 5px 5px 5px;
+       background:#eef8ff;
+       overflow-y:auto;        
+}
+
+div.linkbox {
+       text-align:left;
+  width:350px;
+  margin:10px;
+       }
+       
+div.linkbox h4{
+  text-align:left;
+}
+       
+div.linkbox li {
+    list-style: none;
+}
+
+li a{
+    text-decoration: none;
+    color:#346;
+    font-weight:bold;
+}
+
+li a:hover{
+    text-decoration: none;
+    color:#fa0;
+    font-weight:bold;
+}
+
+       
+ul.optionlist li {
+       width:300px;
+       float:left;
+  list-style:none;
+       }
+
+       
+       
+div.button {
+       position:absolute;
+       background:#def;
+  box-shadow:0px 0px 4px 4px #def;/*, inset 3px 3px 3px 3px #eee, inset -3px -3px 3px 3px #eee;*/
+       top:0px;
+       height:16px;
+       cursor:pointer;
+       font-size:12px;
+       border-width:0 1px 1px 1px;
+       border-radius:0 0 0 5px;
+       color:black;
+}      
+
+div#status {
+/*     float:right; */
+       margin:-20px 15px 10px 15px;
+       padding:10px;
+       width:600px;
+       box-shadow:0px 0px 4px 4px #346;
+       font-family: monospace;
+       color:white;
+       background:#346;
+       border-radius:0 0 5px 5px;      
+}
+
+#status table {
+       vertical-align:top;
+       text-align:left;
+        width:550px;
+}
+
+#status td, #status th {
+       vertical-align:top;
+}
+
+#info {
+       text-align:left;
+       float:left;
+       margin:0;
+       width:480px;
+       background:transparent;
+}
+
+dt {
+       font-weight:bold;
+}
+
+
+
+.bgn {background:#0d0;color:#000;}
+.bye {background:#ff2;color:#000;}
+.bor {background:#fa0;color:#000;}
+.brd, .brdb {background:#f00;}
+.bgr {background:#000;color:#aaa !important;color:#fff;}
+.bwh {background:#eee;color:#000;}
+.bmg {background:#f0a ;color:#000;}
\ No newline at end of file
diff --git a/dmon/code/monitor.pl b/dmon/code/monitor.pl
new file mode 100755 (executable)
index 0000000..04dbced
--- /dev/null
@@ -0,0 +1,182 @@
+#!/usr/bin/perl -w
+use strict;
+use warnings;
+use CGI::Carp qw(fatalsToBrowser);
+my $PATH  = "";
+if ($ENV{'SERVER_SOFTWARE'} =~ /HTTPi/i) {
+  print "HTTP/1.0 200 OK\n";
+  print "Content-type: text/html\r\n\r\n";
+  $PATH = "htdocs/dmon/";
+  }
+else {
+  print "Content-type: text/html\n\n";
+  }
+
+my $out;
+
+my $delay = 10;
+my @args = split('-',$ENV{'QUERY_STRING'});
+
+       if ($args[0] =~ m/^(\d+\.?\d?)$/) {
+               $delay = $1;
+               }
+
+       if( $ENV{'QUERY_STRING'} =~ m/window-/ ) {
+               my $newurl = "monitor.pl?";
+               $newurl .= $ENV{'QUERY_STRING'};
+               $newurl  =~ s/window-//;
+               $newurl =~ /(-|^|\?)(\w+)$/;
+               open(my $MYF,"<$PATH$2.htt");
+               my $str = <$MYF>;
+               close($MYF);
+               $str =~ /width(\d+)\sheight(\d+)/;
+               my $width = 80*$1-8;
+               my $height = 50*$2-8;
+               $out = qq$<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>Dmon</title>
+<meta http-equiv="content-type" content="text/html;charset=UTF-8"/>
+<link href="styles.css" rel="stylesheet" type="text/css"/>
+</head>
+<body >
+<script type="text/javascript">
+  document.write("Opening Window...<br>");
+       win = window.open("$.$newurl.qq$","Dmon$.$newurl.qq$","name=Dmon,innerwidth=$.$width.qq$,innerheight=$.$height.qq$,scrollbars=no,status=no,location=no,menubar=no,resizable=no,titlebar=no,dialog=no");
+       if(win) {
+    win.focus();
+    win.document.title="Dmon $.$newurl.qq#";
+    history.back();
+    }
+  else {
+    document.write("Can't open pop-up window. Please disable pop-up blocker. Starting monitor inline...");
+    setTimeout('window.location.href = "$newurl"',1000);
+    }
+</script>
+#;
+
+             } else {
+
+               $out = qq$<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<!--<meta http-equiv="refresh" content="$.$delay.qq$"/> -->
+<link href="styles.css" rel="stylesheet" type="text/css"/>
+<title>Dmon $.$ENV{'QUERY_STRING'}.qq$</title>
+</head>
+<body ><!--onmousedown="stoprefresh(0);" onmouseup="stoprefresh(0);" ondblclick="stoprefresh(0);"-->
+<div class="button" style="width:45px;right:-8px;" onclick="askclose();">&nbsp;close&nbsp;</div>
+<div class="button" id = "stop" style="right:35px;width:45px;" onclick="stoprefresh(1)">stop</div>
+<div class="button" id = "big" style="right:75px;width:45px;" onclick="zoom();">&nbsp;bigger&nbsp;</div>
+
+<div id="content" class="blinkon"></div>
+$;
+
+
+
+$out .= qq$<script  language='javascript'>
+  var reloadevery = setTimeout('reload()',10);
+  var saveScrollTop = 0;
+  var forcereloadbecauseofmemoryleak = setTimeout("location.reload()",1800000);
+  blinkcnt = 0;
+  blinking = setInterval("blink()",490);
+  currentzoom = 1;
+
+function zoom() {
+       var zoomstep = 1.5;
+       if (currentzoom == 1) {
+               currentzoom = 1.5;
+               document.getElementById('content').style.MozTransform="scale("+currentzoom+")"; 
+               window.innerWidth *= zoomstep;
+               window.innerHeight*= zoomstep;
+               document.getElementById("big").innerHTML = "small";
+               }
+       else {
+               currentzoom = 1;
+               document.getElementById('content').style.MozTransform="scale("+currentzoom+")"; 
+               window.innerWidth /= zoomstep;
+               window.innerHeight/= zoomstep;
+               document.getElementById("big").innerHTML = "bigger";
+               }
+       }
+
+function reload() {
+  xmlhttp=new XMLHttpRequest();
+  xmlhttp.onreadystatechange = function() {
+    if(xmlhttp.readyState == 4) {
+                       document.getElementById("content").innerHTML=xmlhttp.responseText;
+      if(document.getElementById('logbox')) {
+        if(saveScrollTop) {
+          document.getElementById('logbox').scrollTop = saveScrollTop;
+          }
+        }
+
+      document.getElementById("stop").style.background="#444";
+      reloadevery = setTimeout('reload()',$.($delay*1000).qq$);
+      delete xmlhttp;
+      delete saveScrollTop;
+      }
+    };
+  if(document.getElementById('logbox')) {
+    saveScrollTop = document.getElementById('logbox').scrollTop;
+    if (saveScrollTop == 0) {saveScrollTop = 0.1;}
+    }
+  xmlhttp.open("GET","get.pl?$.$ENV{'QUERY_STRING'}.qq$",true);
+  xmlhttp.send(null);
+  document.getElementById("stop").style.background="#111";
+  }
+
+function stoprefresh(button) {
+       if(reloadevery) {
+               clearTimeout(reloadevery);
+               reloadevery = false;
+               document.getElementById("stop").style.background="red";
+               document.getElementById("stop").style.color="white";
+               document.getElementById("stop").innerHTML="cont.";
+               }
+       else {
+               document.getElementById("stop").style.background="#444";
+               document.getElementById("stop").style.color="#aaa";
+               document.getElementById("stop").innerHTML="stop";
+               reload();
+               }
+       return false;
+       }
+
+function askclose() {
+       if(confirm("Close Window?")==true){window.close();}
+       }
+
+function clk(e) {
+  document.getElementById("footer").innerHTML= e.getAttribute("alt");
+  }
+
+function openhelp(w) {
+  x = "monitor.pl?window-"+w;
+  /*y = window.open(x,"DaqMonitor","scrollbars=yes,location=yes,menubar=yes,toolbar=yes");
+  y.focus();*/
+  window.location.href=x;
+  }
+
+
+
+function blink() {
+  if(blinkcnt&1) {
+    document.getElementById('content').setAttribute("class","blinkoff");
+    }
+  else {
+    document.getElementById('content').setAttribute("class","blinkon");
+    }
+  blinkcnt++;
+  }
+
+</script>$;
+             }
+$out .= qq$
+</body>
+</html>
+$;
+
+print $out;
+
diff --git a/dmon/code/styles.css b/dmon/code/styles.css
new file mode 100644 (file)
index 0000000..b44708b
--- /dev/null
@@ -0,0 +1,457 @@
+body {
+  font-family:sans-serif;
+  background:#346;/*#def;*/
+  margin:0px;
+  border:0px;
+  text-align:left;
+  }
+
+body>div>div {
+  float:left;
+  margin: 0px 8px 0px 0;
+  padding: 0 0 0 0 ;
+  border: 1px solid #777;
+  border-width:0 1px 1px 1px;
+  text-align:center;
+  /*box-shadow:1px 1px 4px 4px #eee;/*, inset 3px 3px 3px 3px #eee, inset -3px -3px 3px 3px #eee;*/
+  border-radius: 5px 5px 5px 5px;
+  background:#fff;
+  overflow-y:hidden;  
+  
+}  
+  
+  
+div.timestamp {
+  font-size:11px;
+  color:#888;
+  width: 70px;
+  height:15px;
+  margin:-3px -70px -15px 0;
+  padding:0 0 0 0;
+  border:none;
+  border-top:3px solid #eee;
+  border-radius:0;
+  text-align:center;
+  overflow:hidden;
+}
+
+div.button {
+  position:absolute;
+  top:0px;
+  height:16px;
+  margin: 0px 8px 8px 0;
+  padding: 0 0 0 0 ;
+  cursor:pointer;
+  font-size:12px;
+  color:#aaa;
+  border: 1px solid #777;
+  border-width:0 1px 1px 1px;
+  border-radius:0 5px 0 5px;
+  text-align:center;
+  background:#444;
+  overflow:hidden;
+  z-index:10;
+}
+
+div.errorstamp {
+  font-size:11px;
+  color:red;
+  font-weight:bold;
+  width: 70px;
+  height:15px;
+  margin:-3px -70px -15px 0;
+  padding:0 0 0 0;
+  border:none;
+  border-top:3px solid #eee;
+  border-radius:0;
+  text-align:center;
+  overflow:hidden;
+}
+
+
+div#content {
+    -moz-transform-origin:0 0;
+    -moz-transform:scale(1);  
+}
+
+
+  
+/*
+  //plus 24 in width, plus 29 in height for each size step. 
+  //base is 70x40, 80x50 with border
+ */  
+div.width1  {width:70px;}  
+div.width2  {width:150px;}  
+div.width3  {width:230px;}  
+div.width4  {width:310px;}  
+div.width5  {width:390px;}  
+div.width6  {width:470px;}  
+div.width7  {width:550px;}  
+div.width8  {width:630px;}  
+div.width9  {width:710px;}  
+div.width10 {width:790px;}  
+div.width11 {width:870px;}  
+div.width12 {width:950px;}  
+div.width13 {width:1030px;}  
+div.width14 {width:1110px;}  
+
+div.height1 {height:40px;}      
+div.height2 {height:90px;}    
+div.height3 {height:140px;}    
+div.height4 {height:190px;}    
+div.height5 {height:240px;}  
+div.height6 {height:290px;}  
+div.height7 {height:340px;}  
+div.height8 {height:390px;}  
+div.height9 {height:440px;}  
+div.height10{height:490px;}  
+div.height11{height:540px;}    
+div.height12{height:590px;}    
+div.height13{height:640px;}    
+div.height14{height:690px;}    
+div.height15{height:740px;}    
+div.height16{height:790px;}    
+div.height17{height:840px;}    
+div.height18{height:890px;}    
+div.height19{height:940px;}    
+div.height20{height:990px;}    
+div.height21{height:1040px;}  
+div.height22{height:1090px;}  
+div.height23{height:1140px;}  
+div.height24{height:1190px;}  
+div.height25{height:1240px;}  
+div.height26{height:1290px;}  
+
+
+body>div h3{
+  background:#444;
+  padding:0 0 2px 0;
+  margin: 0 0 0 0;
+  color:#eee;
+  border-radius: 5px 5px 0px 0px;
+  font-size: 13px;
+  cursor:default;
+  }
+
+
+
+table {
+  margin:0;
+  padding:0;
+  }
+    
+
+.textbox, #logbox {  
+  margin:auto;
+  background:white;
+  font-family: monospace;
+  text-align:left;
+  overflow-y:scroll;
+  }
+  
+.height9 .textbox {  height:420px;  }  
+.height6 .textbox {     height:270px;   }       
+.height11 .textbox {     height:520px;   }    
+
+table.rates{
+  border-collapse:collapse;
+  margin:0px 5px 0px 5px;
+  font-size:13px;
+  }
+
+table.rates th {
+  padding:0px 5px;
+}
+
+
+table.rates td{
+}
+
+table.rates th+th, table.rates td+th{
+  font-weight:bold;
+  width:90px;
+  border-bottom:1px solid black;
+  border-left: 1px solid black;
+  }
+  
+table.rates th+td, table.rates td+td {
+  border-left:1px solid black;
+  padding-right:20px;
+  text-align:right;  
+  }
+  
+table.rates td.on {
+  color:#000;
+  background:#dfd;
+
+  }
+
+table.rates td.off {
+  color:#000;
+  background:#fdd;
+}
+
+table.rates .linebelow {
+  border-bottom:1px solid black;
+  }
+
+
+table.mdc td.ctr{
+  background-position: 50% 50%;
+  background-image: url('../mdc.png');
+  background-repeat: no-repeat;
+  }
+
+table.mdc, table.scale, table.colorfields {
+  font-family:monospace;
+  border-collapse:collapse;
+  margin:0px 10px;
+  display:inline-block;
+  }
+  
+table.mdc tr {
+  height:12px;
+  max-height:12px;
+  }
+
+table.mdc td, table.scale td{
+  width: 11px;
+  height: 13px;
+  max-height:12px !important;
+  overflow:hidden;
+  margin: 0;
+  padding: 0px 0 0px 0;
+  color:white;
+  font-size: 8px;
+  border:1px solid white;
+  text-align:center;
+  }
+  
+table.mdc td.ctr {
+  font-size:12px;
+  color:black;
+  }
+  
+
+table.scale {
+  display:block;
+  margin: 10px auto 0 auto;
+  }
+  
+table.scale td {
+  width:13px;
+  }  
+  
+table.scale td.label  {
+  color:black;
+  width:40px;
+  font-size:10px;
+  text-align:right;
+  }
+  
+table.scale td+td+.label  {  
+  text-align:left;
+  }
+  
+
+table.colorfields tr{
+  height:20px;
+  color:black;
+
+  }
+
+table.colorfields td {
+  width:25px;
+  font-size:13px;
+  border:2px solid white;
+  cursor:default;
+  }
+
+table.colorfields th.title {
+/*   width:80px; */
+  margin:0 10px 0 0;
+  padding:0;
+  text-align:right;
+}
+
+table.logfile tr>td {
+  width:150px;
+  vertical-align:top;
+}
+
+table.logfile td+td {
+  width:100px;
+}
+
+table.logfile td+td+td {
+  width:1000px;
+  font-family:monospace;
+  
+}
+
+table.logfile {
+  width:100%;
+  font-size:12px;
+  font-family:sans-serif;
+  border-collapse:collapse;
+  text-align:left;
+}
+
+table.logfile tr {
+  margin:0;
+  padding:0;
+}
+
+table.hubmon {
+  border-collapse:collapse;
+  border:hidden;
+  background:#222;
+  color:white;
+  font-size:11px;
+  width:100%;
+  height:100%;
+  }
+
+table.hubmon td{
+  border-right:1px solid black;
+  border-left:1px solid black;
+  padding:0 15px 0 10px;
+  vertical-align:top;
+  }
+
+.rd  {background-color:#f00;  color:black;}
+.rdn {color:#f00;}
+.gr  {color:#3d3;}
+.or  {color:#fa0;}
+
+.mg {
+  background-color:magenta;
+  color:black;
+}
+
+.wh {
+  color:#ddd;
+}
+
+.bl {
+  color:lightblue;
+}
+
+svg {
+  overflow:hidden;
+  margin:-17px 0px 0px 0;
+  border:0;
+  padding:10px 0 10px 0;
+}
+
+.QA {
+  background:#333;
+  height:100%;
+  width:100%;
+  overflow:hidden;
+}
+
+.QA .header {
+  width: 27px;
+  height:25px;
+  border-radius: 0;
+  -moz-transform: rotate(-90deg);
+  margin:12px -6px 0 6px;
+  font-size:10px;
+  padding:0;
+  border:0;
+  color:white;
+  box-shadow:none;
+}
+
+.QA div{
+  width: 100px;
+  height: 35px;
+  padding:2px 0 0 0;
+  margin:3px 0 0 3px;
+  overflow:hidden;
+  font-size:12px;
+  line-height:1.3;
+  border:0px solid #000;
+  border-collapse:collapse;
+  float:left;
+  border-radius:10px 2px 2px 2px;
+  position:relative;
+  color:black;
+  cursor:default;
+/*   box-shadow:inset  0px 0px 1px 1px #000; */
+}
+
+.bgn {background:#0d0;}
+.byg {background:#ac0;}
+.bye {background:#ff2;}
+.bor {background:#fa0;}
+.brd {background:#f00; }
+.bgr {background:#000;color:#aaa !important;}
+.bwh {background:#eee;}
+.bmg {background:#f0a ;}
+.bbl {background:#9bf};
+
+.blinkon .brdb {
+  background:#f00;
+  color:#000;
+  box-shadow: 0px 0px 3px 3px #f31;
+  z-index:5;
+  }
+
+.blinkoff .brdb {
+  background:#000;
+  color:#f33;
+  }
+
+
+.QA .stamp {
+  color:#aaa;
+  font-size:6px;
+  position:absolute;
+  top:2px;
+  right:0px;
+}
+
+.QA .footer {
+  margin:0;
+/*   position:absolute; */
+/*   left:0; */
+/*   bottom:0; */
+  border:none;
+  border-top:1px solid #aaa;
+  border-radius:0;
+  margin-top:10px;
+  color:white;
+  width:100%;
+  height:100px;
+  font-size:13px;
+  box-shadow:none;
+  clear:both;
+}
+
+
+.greenbutton, .redbutton {
+  width: 20px;
+  height:20px;
+  border-radius:10px;
+  margin:5px 0px 5px 30px;
+}
+
+.greenbutton {
+  background:green;
+}
+
+.redbutton {
+  background:red;
+}
+
+table.status td {
+  text-align:center;
+}
+
+table.status th {
+  min-width:60px;
+  padding-top:5px;
+}
\ No newline at end of file
diff --git a/dmon/example_config.pl b/dmon/example_config.pl
new file mode 100644 (file)
index 0000000..45b53f7
--- /dev/null
@@ -0,0 +1,13 @@
+#This a an example configuration file. Copy this file to your user directory and give 
+#start.pl a link to this file as first argument.
+
+
+activeScripts => [['time','-','-','-','daqop'],
+                  ['numfee','temperature','-','-','-'],
+                  ['trgrate','-','-','-','-'],
+                  ['-','-','-','-','-'],],
+
+qaNames => ['system','main','trigger','-','-','-'],                  
+
+NumberOfFpga => 11,       #Expected number of FPGAs in system
+CtsAddress   => 0x8000,   #The address of the CTS
\ No newline at end of file
diff --git a/dmon/scripts/dmon_numfee.pl b/dmon/scripts/dmon_numfee.pl
new file mode 100755 (executable)
index 0000000..b3b9670
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/perl -w
+
+use warnings;
+use POSIX qw(strftime);
+use FileHandle;
+use lib "./code";
+use HADES::TrbNet;
+use Dmon;
+
+my %config = do $ARGV[0];
+my $flog = Dmon::OpenQAFile();
+trb_init_ports() or die trb_strerror();
+
+
+while(1) {
+  my $r = trb_register_read(0xffff,0);
+  my $num = scalar keys %$r; 
+
+  my $title    = "FPGA #";
+  my $value    = $num."/".$config{NumberOfFpga};
+  my $longtext = $num." out of ".$config{NumberOfFpga}." FPGAs are accessible in the whole system right now.";
+  my $status   = Dmon::GetQAState('above',$num,($config{NumberOfFpga},$config{NumberOfFpga}-1,$config{NumberOfFpga}-2));
+  
+  
+  Dmon::WriteQALog($flog,"numfee",20,$status,$title,$value,$longtext);
+
+  sleep(10);
+}
diff --git a/dmon/scripts/dmon_qa.pl b/dmon/scripts/dmon_qa.pl
new file mode 100755 (executable)
index 0000000..d380518
--- /dev/null
@@ -0,0 +1,91 @@
+#!/usr/bin/perl -w
+use FileHandle;
+use Data::Dumper;
+use POSIX qw(strftime);
+use lib "./code";
+use Dmon;
+
+my %config = do $ARGV[0];
+
+
+while(1) {
+
+open(FLOG, "tail -F ".Dmon::DMONDIR."qalog|") or (sleep(5) and next);
+
+my $readlines = 0;
+my $str = "";
+my $oldtime = time();
+my $store;
+
+my @widthsettings = (3,3,4,5,6,7);
+
+my $width = $widthsettings[scalar @{$config{activeScripts}->[0]}];
+
+
+while($a = <FLOG>) {
+#Store new entries
+  chomp $a;
+  my ($timestamp,$entry,$ttl,$sev,$title,$value,$longtext,$link) = split("\t",$a);
+  $store->{$entry}->{"sev"} = $sev;
+  $store->{$entry}->{"title"} = $title;
+  $store->{$entry}->{"val"} = $value;
+  $store->{$entry}->{"time"} = $timestamp;
+  $store->{$entry}->{"ttl"} = $ttl+$timestamp;
+  $store->{$entry}->{"long"} = $longtext || "No Text";
+  $store->{$entry}->{"link"} = $link;
+
+
+#Delete file if it contains more than 10000 lines
+  if($readlines++ > 10000) {
+    $readlines = 0;
+    close(FLOG);
+    open(FL,">".Dmon::DMONDIR."/qalog");
+    close(FL);
+    open(FLOG, "tail -F ".Dmon::DMONDIR."/qalog|");
+    }
+  my $i = 0;
+#Generate output file at most once per second
+  if(1 || $oldtime < time) {
+    $oldtime = scalar time();
+    $str  = Dmon::MakeTitle($width,7,"Tactical Overview",1);
+    $str .= "<div class=\"QA\">";
+    foreach my $row (@{$config{activeScripts}}) {
+      $str .= "<div class=\"header\" style=\"clear:both\">".($config{qaNames}->[$i++])."</div>\n";
+      foreach my $e (@$row) {
+        my $sev   = $store->{$e}->{'sev'} || 0;
+        my $value = $store->{$e}->{'val'} || "";
+        my $title = $store->{$e}->{'title'} || $e;
+        my $tim   = $store->{$e}->{'time'} || -1;
+        my $time  = strftime("(%H:%M:%S)",localtime($tim)) if $tim != -1;
+           $time  = "" if $tim == -1;
+        my $text  = $store->{$e}->{'long'} || "";
+        my $ttl   = $store->{$e}->{'ttl'} || 0;
+        my $link  = $store->{$e}->{'link'} || "";
+        
+        if (!defined($sev)||$sev==Dmon::NA) {$sevcol = "bgr";}
+        elsif ($ttl < $oldtime)             {$sevcol = "bwh";}
+        elsif ($sev == Dmon::NOSTATE)       {$sevcol = "bbl";}
+        elsif ($sev == Dmon::SCRIPTERROR)   {$sevcol = "bmg";}
+        elsif ($sev < Dmon::NOTE)           {$sevcol = "bgn";}
+        elsif ($sev < Dmon::WARN)           {$sevcol = "byg";}
+        elsif ($sev < Dmon::WARN_2)         {$sevcol = "bye";}
+        elsif ($sev < Dmon::ERROR)          {$sevcol = "bor";}
+        elsif ($sev < Dmon::LETHAL)         {$sevcol = "brd";}
+        elsif ($sev == Dmon::LETHAL)        {$sevcol = "brdb";}
+        else                              {$sevcol = "bgr";}
+
+        
+        $str .= "<div id=\"$e\" class=\"".($sev||0)." $sevcol\" alt=\"$title $time: ".Dmon::LevelName($sev)."&lt;br /&gt; $text\" onmouseover=\"clk(this);\"";
+        $str .= "onclick=\"openhelp('$link')\" >".$title."<br/>".$value."</div>\n";
+        }
+      }
+    $str .="<div id=\"footer\" class=\"footer\"></div></div>";
+
+    $str .= Dmon::MakeFooter();
+    Dmon::WriteFile("QA",$str);      
+     
+    }
+  }
+  sleep(5);
+}
diff --git a/dmon/scripts/dmon_temperature.pl b/dmon/scripts/dmon_temperature.pl
new file mode 100755 (executable)
index 0000000..4beb463
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/perl -w
+
+use warnings;
+use lib "./code";
+use HADES::TrbNet;
+use Dmon;
+use Data::Dumper;
+
+my %config = do $ARGV[0];
+my $flog = Dmon::OpenQAFile();
+trb_init_ports() or die trb_strerror();
+
+
+while(1) {
+  my $r = trb_register_read(0xffff,0);
+  my $max = 0; 
+  my $min = 100;  
+  my ($maxboard, $minboard);
+#   print Dumper $r;
+  foreach my $b (keys %$r) {
+    my $temp = (($r->{$b} & 0xFFF00000)>>20)/16;
+    if ($max < $temp) {
+      $max = $temp;
+      $maxboard = $b;
+      }
+    elsif ($min > $temp) { 
+      $min = $temp;
+      $minboard = $b;
+      }
+    print STDERR $temp." ".$min."\n";
+    }
+  
+  my $title    = "Temperature";
+  my $value    = sprintf("%.1f",$max);
+  my $longtext = sprintf("Maximum: %.1f on board 0x%04x<br>Minimum: %.1f on board 0x%04x",$max,$maxboard,$min,$minboard);
+  my $status   = Dmon::GetQAState('below',$max,(60,75,80));
+  
+  
+  Dmon::WriteQALog($flog,"temperature",20,$status,$title,$value,$longtext);
+
+  sleep(10);
+}
diff --git a/dmon/scripts/dmon_time.pl b/dmon/scripts/dmon_time.pl
new file mode 100755 (executable)
index 0000000..49b14e1
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+
+use warnings;
+use strict;
+use POSIX qw(strftime);
+use FileHandle;
+use lib "./code";
+use Dmon;
+
+use Getopt::Long;
+
+my $flog = Dmon::OpenQAFile();
+
+Dmon::WriteQALog($flog,"daqop",100000000,Dmon::NOSTATE,"trbnetd",$ENV{"DAQOPSERVER"},"Trbnet daemon is accessed via ".$ENV{"DAQOPSERVER"});
+
+
+
+while(1) {
+  my $title    = "Wall Clock";
+  my $value    = strftime("%H:%M:%S", localtime());
+  my $longtext = "This is a good time to work.";
+  Dmon::WriteQALog($flog,"time",10,Dmon::OK,$title,$value,$longtext);
+
+  sleep(2);
+}
diff --git a/dmon/scripts/dmon_trgrate.pl b/dmon/scripts/dmon_trgrate.pl
new file mode 100755 (executable)
index 0000000..f02d3eb
--- /dev/null
@@ -0,0 +1,70 @@
+#!/usr/bin/perl -w
+
+use warnings;
+use POSIX qw(strftime);
+use FileHandle;
+use lib "./code";
+use lib "../tools";
+use HADES::TrbNet;
+use Time::HiRes qw(usleep);
+use Dmon;
+use HPlot;
+
+my %config = do $ARGV[0];
+my $flog = Dmon::OpenQAFile();
+trb_init_ports() or die trb_strerror();
+
+my $old;
+my $summing = 0;
+my $cnt = 0;
+
+
+my $plot = ();
+$plot->{name}    = "TriggerRate";
+$plot->{file}    = Dmon::DMONDIR."TriggerRate";
+$plot->{entries} = 600;
+$plot->{type}    = HPlot::TYPE_HISTORY;
+$plot->{output}  = HPlot::OUT_PNG;
+$plot->{titles}->[0] = "";
+$plot->{xlabel}  = "Time [s]";
+$plot->{ylabel}  = "Rate [Hz]";
+$plot->{sizex}   = 750;
+$plot->{sizey}   = 270;
+$plot->{xscale}  = 5;
+$plot->{nokey}   = 1;
+$plot->{buffer}  = 1;
+HPlot::PlotInit($plot);
+
+my $str = Dmon::MakeTitle(10,6,"TriggerRate",0);
+   $str .= qq@<img src="%ADDPNG TriggerRate.png%" type="image/png">@;
+   $str .= Dmon::MakeFooter();
+Dmon::WriteFile("TriggerRate",$str);
+
+
+
+
+while(1) {
+  my $r = trb_register_read($config{CtsAddress},0xa000);
+  my $value    = $r->{$config{CtsAddress}};
+  my $rate     = ($value||0) - ($old||0);
+     $rate += 2**32 if $rate < 0;
+  
+  if( defined $old) {
+    $summing += $rate;
+    HPlot::PlotAdd('TriggerRate',$rate*5,0);
+    print $rate;
+    
+    unless($cnt++ % 10) {
+      my $title    = "Rate";
+      my $value    = $summing/2;
+      my $longtext = $value." triggers pre second";
+      my $status   = Dmon::GetQAState('above',$value,(15,2,1));
+      Dmon::WriteQALog($flog,"trgrate",5,$status,$title,$value,$longtext,'2-TriggerRate');
+      HPlot::PlotDraw('TriggerRate');
+      $summing = 0;
+      }
+    }
+  $old = $value;    
+  usleep(200000);
+}
diff --git a/dmon/start.pl b/dmon/start.pl
new file mode 100755 (executable)
index 0000000..3ac7c6d
--- /dev/null
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+
+use warnings;
+use lib "./code";
+use Dmon;
+use Data::Dumper;
+
+my %config;
+
+if(defined $ARGV[0]) {
+  print "Loading settings from $ARGV[0]\n";
+  %config = do $ARGV[0];
+  }
+else {
+  die "Configuration file needed\n";
+  }
+  
+# $config{activeScripts} = [['time'],['-']];  
+  
+# print Dumper $config{activeScripts};
+
+# exit;
+
+print "  <Dmon>     Creating Files and Links...\n";
+
+system("mkdir -p /dev/shm/dmon");
+system("mkdir -p /tmp/dmonlogs");
+system("ln -fs /dev/shm/dmon ../web/htdocs/dmon");
+# system("ln -fs /tmp/dmonlogs /dev/shm/dmon/logs");
+system("ln -fs `pwd`/code /dev/shm/dmon/");
+system("ln -fs `pwd`/code/index.pl /dev/shm/dmon/index.pl");
+
+print "  <Dmon>     Starting scripts...\n";
+
+print "Starting QA\n";
+system("scripts/dmon_qa.pl $ARGV[0] 2>>/tmp/dmonlogs/qa_log.txt &");
+
+my $r, my @l;
+foreach my $row (@{$config{activeScripts}}) {
+  foreach my $script (@$row) {
+    next if $script eq '-';
+    $r=fork(); 
+    push(@l, $r); 
+    if($r == 0) { 
+      print "\t\tRunning ".$script."\n"; 
+      system("killall dmon_$script.pl");
+      system("scripts/dmon_$script.pl $ARGV[0] 2>>/tmp/dmonlogs/".$script."_log.txt"); 
+      exit;
+      } 
+    }
+  }
+END: {if($r!=0 and eof()) {foreach (@l) {wait}}}
+
+
diff --git a/dmon/stop.pl b/dmon/stop.pl
new file mode 100755 (executable)
index 0000000..bcd3e53
--- /dev/null
@@ -0,0 +1,4 @@
+#!/usr/bin/perl
+
+
+system("cd scripts; killall dmon_*; cd ..;");
\ No newline at end of file
diff --git a/tools/HPlot.pm b/tools/HPlot.pm
new file mode 100755 (executable)
index 0000000..a4c55ff
--- /dev/null
@@ -0,0 +1,275 @@
+package HPlot;
+use POSIX qw/floor ceil strftime/;
+use Data::Dumper;
+use warnings;
+use strict;
+use FileHandle;
+use Storable qw(lock_store lock_retrieve);
+
+my $p;
+my $storefile;
+
+use constant {TYPE_HISTORY => 1, TYPE_BARGRAPH => 2, TYPE_HEATMAP => 3};
+
+use constant {OUT_PNG    => 1,
+              OUT_SVG    => 2,  #n/a
+              OUT_SCREEN => 3}; #n/a
+
+my @color= ('#2222dd','#dd2222','#22dd22','#dd8822','#dd22dd','#22dddd','#dddd22','#8888dd','#8822bb','#444444');
+
+sub plot_write {
+  my ($file,$str,$no) = @_;
+  return unless $str;
+  if($no || 0) {
+    print $file $str;
+#     print $str;
+    }
+  else {
+    print $file $str."\n";
+#     print $str."\n";
+    }
+  }
+
+
+sub makeTimeString{
+  return strftime("set label 100 \"%H:%M:%S\" at screen 0.02,0.02 left tc rgb \"#000044\" font \"monospace,8\"\n", localtime())
+  }
+
+
+sub PlotInit {
+  my ($c) = @_;
+
+  my $name      = $c->{name};
+
+  my $fn = "gnuplot";
+  #my $fh = new FileHandle ("|$fn") or  die "error: no gnuplot";
+  open my $fh, "|$fn" or  die "error: no gnuplot";
+  $fh->autoflush(1);
+
+
+  $p->{$name} = $c;
+  $p->{$name}->{fh} = $fh;
+  $p->{$name}->{run} = 0;
+  $p->{$name}->{buffer} = $p->{$name}->{buffer} || 0;
+  $p->{$name}->{sizex} = $p->{$name}->{sizex} || 600 ;
+  $p->{$name}->{sizey} = $p->{$name}->{sizey} || 400 ;
+  $p->{$name}->{file} = $p->{$name}->{file} || "dummy" ;
+  $p->{$name}->{curves} = $p->{$name}->{curves} || 1 ;
+  $p->{$name}->{xscale} = $p->{$name}->{xscale} || 1;
+  $p->{$name}->{type}   or die "No plot type specified";
+  $p->{$name}->{output} or die "No destination specified";
+  $p->{$name}->{colors} = $p->{$name}->{colors} || \@color;
+  $p->{$name}->{showvalues} = $p->{$name}->{showvalues} || 0;
+  $p->{$name}->{storable} = $p->{$name}->{storable} || 0;
+
+  my $filename = $p->{$name}->{file};
+  $filename =~ s%/%%;
+  $storefile->{$name} = "/dev/shm/".$name.'-'.$p->{$name}->{curves}.'-'.$p->{$name}->{entries}.'-'.$filename.'.store';
+
+    
+  foreach my $i (0..($c->{entries}-1)) {
+    for my $j (0..($c->{curves}-1)) {
+      push(@{$p->{$name}->{value}->[$j]},0) ;
+      }
+    }
+  
+  if($p->{$name}->{storable}) {
+    if (-e $storefile->{$name}) {
+      $p->{$name}->{value} = lock_retrieve($storefile->{$name});
+      }
+    }
+
+
+  if($p->{$name}->{output} == OUT_PNG) {
+    $p->{$name}->{file} or die "No filename specified";
+    plot_write($fh,"set term png size ".$p->{$name}->{sizex}.",".$p->{$name}->{sizey}." font \"monospace,8\"");
+    plot_write($fh,"set out \"".$p->{$name}->{file}.($p->{$name}->{buffer}?"tmp":"").".png\"");
+    }
+  elsif($p->{$name}->{output} == OUT_SCREEN) {
+    plot_write($fh,"set term x11 size ".$p->{$name}->{sizex}.",".$p->{$name}->{sizey});
+    }
+  else {
+    die "Output mode not supported yet";
+    }
+
+  if  ($p->{$name}->{nokey}) {
+    plot_write($fh,"unset key");
+    }
+  else {
+    plot_write($fh,"set key left top");
+    }
+
+
+  plot_write($fh,"set xlabel \"".$p->{$name}->{xlabel}."\"") if $p->{$name}->{xlabel};
+  plot_write($fh,"set ylabel \"".$p->{$name}->{ylabel}."\"") if $p->{$name}->{ylabel};
+
+  if(defined $p->{$name}->{ymin} && defined $p->{$name}->{ymax}) {
+    plot_write($fh,"set yrange [".$p->{$name}->{ymin}.":".$p->{$name}->{ymax}."]");
+    }
+  elsif(defined $p->{$name}->{ymax}) {
+    plot_write($fh,"set yrange [:".$p->{$name}->{ymax}."]");
+    }
+  elsif(defined $p->{$name}->{ymin}) {
+    plot_write($fh,"set yrange [".$p->{$name}->{ymin}.":]");
+    }
+
+  if(defined $p->{$name}->{xmin} && defined $p->{$name}->{xmax}) {
+    plot_write($fh,"set xrange [".$p->{$name}->{xmin}.":".$p->{$name}->{xmax}."]");
+    }
+  elsif(defined $p->{$name}->{xmax}) {
+    plot_write($fh,"set xrange [:".$p->{$name}->{xmax}."]");
+    }
+  elsif(defined $p->{$name}->{xmin}) {
+    plot_write($fh,"set xrange [".$p->{$name}->{xmin}.":]");
+    }
+    
+  if($p->{$name}->{type} == TYPE_HISTORY) {
+    if($p->{$name}->{fill}) {
+      plot_write($fh,"set style fill solid 1.00");
+      }
+    else {
+      plot_write($fh,"set style fill solid 0");
+      }
+    plot_write($fh,"set boxwidth 2 absolute");
+    plot_write($fh,"set autoscale fix");
+    plot_write($fh,"set xtics autofreq"); #$p->{$name}->{entries}
+    plot_write($fh,"set grid");
+#     plot_write($fh,"set style fill solid 1.0");
+    plot_write($fh,"plot ",1);
+    for(my $j=0; $j<$p->{$name}->{curves};$j++) {
+      if($p->{$name}->{fill}) {
+        plot_write($fh,"'-' using 1:2 with filledcurves x1 lt rgb \"".$p->{$name}->{colors}->[$j]."\" title \"".($p->{$name}->{titles}->[$j] || "$j")."\" ",1);
+        }
+      elsif($p->{$name}->{dots}) {
+        plot_write($fh,"'-' using 1:2 with points pointsize 0.6 pointtype 2 lt rgb \"".$p->{$name}->{colors}->[$j]."\" title \"".($p->{$name}->{titles}->[$j] || "$j")."\" ",1);
+        }
+      else {
+        plot_write($fh,"'-' using 1:2 with lines  lt rgb \"".$p->{$name}->{colors}->[$j]."\" title \"".($p->{$name}->{titles}->[$j] || "$j")."\" ",1);
+        }
+      plot_write($fh,', ',1) unless ($j+1==$p->{$name}->{curves});
+      }
+    plot_write($fh," ");
+    }
+  elsif($p->{$name}->{type} == TYPE_BARGRAPH) {
+    plot_write($fh,"set style fill   solid 1.00 border -1");
+    plot_write($fh,"set grid noxtics ytics");
+    plot_write($fh,"set boxwidth ".($p->{$name}->{curvewidth}||4)." absolute");
+    plot_write($fh,"set style histogram gap ".($p->{$name}->{bargap}||1));
+    if(defined $p->{$name}->{bartitle} && scalar @{$p->{$name}->{bartitle}}) {
+      plot_write($fh,"set xtics (",1);
+      for(my $j=0; $j<scalar @{$p->{$name}->{bartitle}};$j++) {
+        plot_write($fh,', ',1) if $j;
+        plot_write($fh,"'".$p->{$name}->{bartitle}->[$j]."' $j ",1);
+        }
+      plot_write($fh,") offset 2.5,0 scale 0");
+      }
+    plot_write($fh,"set style histogram title offset character 0, 0, 0");
+    plot_write($fh,"set style data histograms");
+    plot_write($fh,"plot ",1);
+    for(my $j=0; $j<$p->{$name}->{curves};$j++) {
+      plot_write($fh,', ',1) if $j;
+      plot_write($fh,"'-' lt rgb \"".$p->{$name}->{colors}->[$j]."\" title \"".($p->{$name}->{titles}->[$j] || "$j")."\" ",1);
+      }
+    plot_write($fh," ");
+    }
+  elsif($p->{$name}->{type} == TYPE_HEATMAP) {
+    plot_write($fh,"set view map");
+    plot_write($fh,"set palette rgbformulae 22,13,-31");
+    if ($p->{$name}->{showvalues} == 0) {
+      plot_write($fh,"splot '-' matrix with image");
+      }
+    else {
+      plot_write($fh,"plot '-' matrix with image, '-' matrix using 1:2:(sprintf('%i', \$3)) with labels tc rgb \"#ffffff\" font ',10'");
+      }
+    }
+  else {
+    die "Plot type not supported";
+    }
+
+  }
+
+
+sub PlotDraw {
+  my($name) = @_;
+  if($p->{$name}->{buffer} && -e $p->{$name}->{file}."tmp.png") {  
+    rename $p->{$name}->{file}."tmp.png", $p->{$name}->{file}.".png";
+    }
+  if($p->{$name}->{run}>=1) {
+    plot_write($p->{$name}->{fh},"set out \"".$p->{$name}->{file}.($p->{$name}->{buffer}?"tmp":"").".png\"");
+    plot_write($p->{$name}->{fh},makeTimeString());
+    plot_write($p->{$name}->{fh},"replot");
+    }
+    
+  if($p->{$name}->{type} == TYPE_HISTORY) {  
+    for(my $j=0; $j<$p->{$name}->{curves}; $j++) {
+      for(my $i=0; $i< $p->{$name}->{entries}; $i++) {
+        if ($p->{$name}->{countup}) {
+          plot_write($p->{$name}->{fh},($i/$p->{$name}->{xscale})." ".$p->{$name}->{value}->[$j]->[$i]);
+          }
+        else {
+          plot_write($p->{$name}->{fh},(($i-$p->{$name}->{entries})/$p->{$name}->{xscale})." ".$p->{$name}->{value}->[$j]->[$i]);
+          }
+        }
+      plot_write($p->{$name}->{fh},"e");
+      }  
+    }
+    
+    
+  if($p->{$name}->{type} == TYPE_BARGRAPH) { 
+    for(my $j=0; $j<$p->{$name}->{curves}; $j++) {
+      for(my $i=0; $i< $p->{$name}->{entries}; $i++) {
+        plot_write($p->{$name}->{fh},' '.$p->{$name}->{value}->[$j]->[$i]);
+        }
+      plot_write($p->{$name}->{fh},"e");
+      }
+    }
+      
+      
+  if($p->{$name}->{type} == TYPE_HEATMAP) {    
+      for(my $j=0; $j<$p->{$name}->{curves}; $j++) {
+        for(my $i=0; $i< $p->{$name}->{entries}; $i++) {
+          plot_write($p->{$name}->{fh},($p->{$name}->{value}->[$j]->[$i]||0)." ",1);
+          }
+        plot_write($p->{$name}->{fh}," ",0);
+        }
+      plot_write($p->{$name}->{fh},"e");      
+      plot_write($p->{$name}->{fh},"e");     
+#       }
+      for(my $j=0; $j<$p->{$name}->{curves}; $j++) {
+        for(my $i=0; $i< $p->{$name}->{entries}; $i++) {
+          plot_write($p->{$name}->{fh},($p->{$name}->{value}->[$j]->[$i]||0)." ",1);
+          }
+        plot_write($p->{$name}->{fh}," ",0);
+        }
+      plot_write($p->{$name}->{fh},"e");      
+      plot_write($p->{$name}->{fh},"e");     
+
+    }
+    
+    
+  $p->{$name}->{run}++;
+  
+  
+  if($p->{$name}->{storable}) {
+    lock_store($p->{$name}->{value},$storefile->{$name});
+    }
+  }
+
+
+sub PlotAdd {
+  my($name,$value,$curve) = @_;
+  $curve = 0 unless $curve;
+
+  push(@{$p->{$name}->{value}->[$curve]},$value||0);
+  shift(@{$p->{$name}->{value}->[$curve]});
+
+  }
+
+sub PlotFill {
+  my($name,$value,$slot,$curve) = @_;
+  $curve = 0 unless $curve;
+  $p->{$name}->{value}->[$curve]->[$slot] = $value||0;
+  }
+  
+
+1;
diff --git a/web/htdocs/dmon b/web/htdocs/dmon
new file mode 120000 (symlink)
index 0000000..6c94635
--- /dev/null
@@ -0,0 +1 @@
+/dev/shm/dmon
\ No newline at end of file