From: Jan Michel Date: Thu, 10 Jul 2014 18:32:47 +0000 (+0200) Subject: added Tactical monitor from Hades to daqtools X-Git-Url: https://jspc29.x-matter.uni-frankfurt.de/git/?a=commitdiff_plain;h=4fa0f738f2bb0cce705783ccf5f720ab0186e119;p=daqtools.git added Tactical monitor from Hades to daqtools --- diff --git a/.gitignore b/.gitignore index e638d20..86f9099 100644 --- a/.gitignore +++ b/.gitignore @@ -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 index 0000000..1b69ba7 --- /dev/null +++ b/dmon/code/Dmon.pm @@ -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 = "
\n"; + if ($time) { + $str .= "
".strftime("%H:%M:%S", localtime())."
\n"; + } + if (defined $error && $error ne "") { + $str .= "
$error
\n"; + } + $str .= "

$title

"; + return $str; +} + +sub MakeFooter { + my $str; + $str = "
\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 index 0000000..c728aa7 --- /dev/null +++ b/dmon/code/get.pl @@ -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/ + + +Monitoring Main Control Interface + + + + + +
+

DAQ Monitoring

+ + + + + + + + +$; + + +print "

All available options


\n"; + + + +#

Help

+#To select the information you want to have, specify any number of the options listed below, separated with '-' after the \"monitor.cgi?\".

+#

+#
Hints
+# +#
Examples
+# +print qq$ + + +$; diff --git a/dmon/code/indexstyles.css b/dmon/code/indexstyles.css new file mode 100644 index 0000000..32e5f02 --- /dev/null +++ b/dmon/code/indexstyles.css @@ -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 index 0000000..04dbced --- /dev/null +++ b/dmon/code/monitor.pl @@ -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$ + + +Dmon + + + + + +#; + + } else { + + $out = qq$ + + + + + +Dmon $.$ENV{'QUERY_STRING'}.qq$ + + +
 close 
+
stop
+
 bigger 
+ +
+$; + + + +$out .= qq$$; + } +$out .= qq$ + + +$; + +print $out; + diff --git a/dmon/code/styles.css b/dmon/code/styles.css new file mode 100644 index 0000000..b44708b --- /dev/null +++ b/dmon/code/styles.css @@ -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 index 0000000..45b53f7 --- /dev/null +++ b/dmon/example_config.pl @@ -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 index 0000000..b3b9670 --- /dev/null +++ b/dmon/scripts/dmon_numfee.pl @@ -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 index 0000000..d380518 --- /dev/null +++ b/dmon/scripts/dmon_qa.pl @@ -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 = ) { +#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 .= "
"; + foreach my $row (@{$config{activeScripts}}) { + $str .= "
".($config{qaNames}->[$i++])."
\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 .= "
".$title."
".$value."
\n"; + } + + } + $str .="
"; + + $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 index 0000000..4beb463 --- /dev/null +++ b/dmon/scripts/dmon_temperature.pl @@ -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
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 index 0000000..49b14e1 --- /dev/null +++ b/dmon/scripts/dmon_time.pl @@ -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 index 0000000..f02d3eb --- /dev/null +++ b/dmon/scripts/dmon_trgrate.pl @@ -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@@; + $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 index 0000000..3ac7c6d --- /dev/null +++ b/dmon/start.pl @@ -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 " 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 " 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 index 0000000..bcd3e53 --- /dev/null +++ b/dmon/stop.pl @@ -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 index 0000000..a4c55ff --- /dev/null +++ b/tools/HPlot.pm @@ -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{$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 index 0000000..6c94635 --- /dev/null +++ b/web/htdocs/dmon @@ -0,0 +1 @@ +/dev/shm/dmon \ No newline at end of file