#!/usr/bin/perl -w
########################################################################
# Get Ayecka SR1 status
#
# Version v1.4a, 15-04-2016
#
# Copyright (C) 2015 Rob Alblas
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# For details of the GNU General Public License see
# http://perldoc.perl.org/perlgpl.html, or write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# 
########################################################################
# Use: sr1_status.pl
#  or:  perl sr1_status.pl
#
# Argument: 
#     -h    help
#     -ip   <ip_nr> set ip nr. (def.: 192.168.10.99)       
#     -bs   <size > set size of big SNR (def.: 120)        
#     -sr   <sample_rate> sample rate in msec (def.: 1000) 
#
########################################################################
use Tk;
use Tk::Table;
use Net::SNMP;
use strict;
my $bitrate_pre=0;
my $bitrate_cnt=0;
my $def_srate=1000;           # sample rate in ms
my $def_ip="192.168.10.99";   # default IP address
my $def_snrsize=120;          # default big SNR size

my $use_singleSNMP = 0;       # 0: use multiple SNMP in one request 

# codes:
# sr1				=101
# sr1.configuration		=101.1
# sr1.configuration.rx1		=101.1.1
# sr1.configuration.rx1.rx1_cfg2=101.1.1.2

# base oid's Ayecka SR1
my $PREOID        = "1.3.6.1.4.1.27928.101.1.1";   # 101.1.1=sr1.config.rx1
my $PREOIDC       = "1.3.6.1.4.1.27928.101.1.1.2"; # 101.1.2=sr1.config.rx1.rx1_cfg2
my $PREOID2       = "1.3.6.1.4.1.27928.101.2";     # 101.2  =sr1.network
my $PREOID3       = "1.3.6.1.4.1.27928.101.3";     # 101.3  =sr1.system
my $PREOID9       = "1.3.6.1.2.1.2.2.1";           # others

# Next are oid's of SR1.
# rx1_status = 4.
my $TUNERSTAT     = "4.1";
my $FREQOFFSET    = "4.2";
my $POWERLEVEL    = "4.3";
my $SNR           = "4.4";
my $BER           = "4.5";
my $LINKMARG      = "4.6";
my $MODCOD        = "4.7";
my $ROLLOFFSTAT   = "4.8";
my $PILOTSTAT     = "4.9";
my $FRAMETYPESTAT = "4.10";
my $DEMODSTAT     = "4.11";
my $CRCERR        = "4.12";
my $TRANSPSTAT    = "4.13";
my $BADFRMCNT     = "4.15";
my $BADPCKTCNT    = "4.16";
my $LINKMARGL     = "100";  # artifical 'oid'
my $LINKMARGH     = "101";  # artifical 'oid'
my $INFO          = "102";  # artifical 'oid'
my $SW_VERS       = "5.0";
my $FPGA_VERS     = "6.0";
my $HW_VERS       = "7.0";
my $BITRATE       = "16.1";

# config2=active
# rx1_cfg2 = 2
# rx1_cfg2_demod = 2.2
# rx1_cfg2_transport = 2 4
my $Signal_Standard = "2.2.1";
my $Signal_Rate = "2.2.2";
my $Coding_Mode1 = "1.2.3";
my $Coding_Mode = "2.2.3";
my $Table_of_filters = "2.4.3";

##########################################################################
# Start itemms to adapt
##########################################################################
#Next defines one item to display big.
my $bigitem=$SNR;
my $bigitemname="SNR"; # name of button

# Load all items to catch into array.
sub load_cmds_info
{
# Add items, remove items, change order as desired.
  my @a_mng=
  (
#    {name=>"Info "         ,id=>0 ,oid_part=>$INFO          ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"SW version"    ,id=>3 ,oid_part=>$SW_VERS       ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"HW version"    ,id=>3 ,oid_part=>$HW_VERS       ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"FPGA version"  ,id=>3 ,oid_part=>$FPGA_VERS     ,ifs=>0,ival=>0,fval=>0.0,sval=>""}
#    {name=>"ROLLOFFSTAT"   ,id=>1 ,oid_part=>$ROLLOFFSTAT   ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
#    {name=>"PILOTSTAT"     ,id=>1 ,oid_part=>$PILOTSTAT     ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
#    {name=>"FRAMETYPESTAT" ,id=>1 ,oid_part=>$FRAMETYPESTAT ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
#    {name=>"DEMODSTAT"     ,id=>1 ,oid_part=>$DEMODSTAT     ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
#    {name=>"TRANSPSTAT"    ,id=>1 ,oid_part=>$TRANSPSTAT    ,ifs=>0,ival=>0,fval=>0.0,sval=>""}
  );
  return @a_mng;
}


#bit_rate: wordt elke 3 sec. opgehoogd, hoe dit te gebruiken??? max. 10 cijfers, tot ca.  4.292.093.526
# 13716720 13716720 29231954 29231954 29231954 40256932 40256932 51094100 enz.
# 6476527 6476527 6476527 21296272 21296272 34950918 enz.
# Komt niet overeen met 'Traffic' in sr1-controller die bovendien elke sec. nieuwe waardes geeft....
sub load_cmds_status
{
  my @a_mng=
  (
    {name=>"Info "         ,id=>-11 ,oid_part=>$INFO          ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"Tuner"         ,id=>1 ,oid_part=>$TUNERSTAT     ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"SNR"           ,id=>1 ,oid_part=>$SNR           ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"Power"         ,id=>1 ,oid_part=>$POWERLEVEL    ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"MODCOD"        ,id=>1 ,oid_part=>$MODCOD        ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"LINKMARG"      ,id=>1 ,oid_part=>$LINKMARG      ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"Linkmarg. L"   ,id=>-1 ,oid_part=>$LINKMARGL     ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"Linkmarg. H"   ,id=>-1 ,oid_part=>$LINKMARGH     ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"Bit rate"      ,id=>9 ,oid_part=>$BITRATE       ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"BER"           ,id=>1 ,oid_part=>$BER           ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"CRCErr"        ,id=>1 ,oid_part=>$CRCERR        ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"Bad FRM CNT"   ,id=>1 ,oid_part=>$BADFRMCNT     ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"Bad PCKT CNT"  ,id=>1 ,oid_part=>$BADPCKTCNT    ,ifs=>0,ival=>0,fval=>0.0,sval=>""}

#    {name=>"ROLLOFFSTAT"   ,oid_part=>$ROLLOFFSTAT   ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
#    {name=>"PILOTSTAT"     ,oid_part=>$PILOTSTAT     ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
#    {name=>"FRAMETYPESTAT" ,oid_part=>$FRAMETYPESTAT ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
#    {name=>"DEMODSTAT"     ,oid_part=>$DEMODSTAT     ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
#    {name=>"TRANSPSTAT"    ,oid_part=>$TRANSPSTAT    ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
  );

  return @a_mng;
}

sub load_cmds_control
{
  my @a_mng=
  (
#    {name=>"MODCOD"        ,id=>1 ,oid_part=>$MODCOD                  ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"Signal status"  ,id=>1 ,oid_part=>$Signal_Standard        ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"Signal Rate"    ,id=>1 ,oid_part=>$Signal_Rate            ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
    {name=>"Coding Mode"    ,id=>1 ,oid_part=>$Coding_Mode            ,ifs=>0,ival=>0,fval=>0.0,sval=>""},
#    {name=>"Coding Mode1"    ,id=>1 ,oid_part=>$Coding_Mode1            ,ifs=>0,ival=>0,fval=>0.0,sval=>""}
#   {name=>"Table filters"  ,id=>1 ,oid_part=>$Table_of_filters       ,ifs=>0,ival=>0,fval=>0.0,sval=>""}
  );
  return @a_mng;
}

##########################################################################
# End itemms to adapt
##########################################################################

my $session;   
#my @am;        # list of all items to catch
my @ama;        # list of all items to catch
my @amb;        # list of all items to catch
my @amc;        # list of all items to catch
my @varbindlista;
my @varbindlistb;
my @varbindlistc;

sub is_oid
{
  my $item=($_=shift);
 
  if ($item->{id} <0)
  {
    return 0;
  }
  return 1;
}

sub mk_oid
{
  my $item=($_=shift);
  my $oid1;
  if ($item->{id} == 1)
  {
    $oid1=sprintf("%s.%s.0",$PREOID,$item->{oid_part});
  }
  elsif ($item->{id} == 2)
  {
    $oid1=sprintf("%s.%s",$PREOID2,$item->{oid_part});
  }
  elsif ($item->{id} == 9)
  {
    $oid1=sprintf("%s.%s",$PREOID9,$item->{oid_part});
  }
  else
  {
    $oid1=sprintf("%s.%s",$PREOID3,$item->{oid_part});
  }
  return $oid1;
}

# Create list of all oid's to catch
sub create_snmplist
{
  my ($amx)=@_;
  my @varbindlist1;
  my $i;
  foreach $i (@$amx)
  {
    if (is_oid($i))
    {
      my $oid=mk_oid($i);
      $varbindlist1[++$#varbindlist1]=$oid;
    }
  }
  return @varbindlist1;
}

# Init the SNMP session.
# Arg.: hostname IP
#
sub snmp_sess_init
{
  my $ip=$_[0];
  my $community="public";
  my $session1;
  my $error;
  ($session1, $error) = Net::SNMP->session(
                         -hostname      => $ip,
                         -version       => 2,
                         -community     => $community 
                       );
  $session1->timeout(1);
  return $session1;
}

# Get vals 1 by 1.
sub get_stats_1by1
{
  my ($modcod,$lm);
  my $i;
  my $try;
  $lm=0;
  do
  {
    foreach $i (@amb)
    {
      if ($i->{oid_part} == $MODCOD)
      {
        $modcod=$i->{ival};
      }
    }
    foreach $i (@amb)
    {
      if (is_oid($i))
      {
        my $oid=mk_oid($i);
#        my $oid=sprintf("%s.%s.0",$PREOID,$i->{oid_part});
        my $req;
        my $err;
        $req=$session->get_request($oid);
        $err=$session->error();
        if (!defined $req)
        {
          return 1;
        }
        else
        {
          $i->{ival}=${$req}{$oid};
          # store marg.
          if ($i->{oid_part} == $LINKMARG)
          {
            $lm=$i->{ival};
          }
        }
      }
    }

    $try=0;
    foreach $i (@amb)
    {
      if ($i->{oid_part} == $MODCOD)
      {
        if ($modcod != $i->{ival}) { $try=1; }
      }
    }
  } while ($try);

  foreach $i (@amb)
  {
    if (($i->{oid_part} == $LINKMARGL) && ($modcod==12))
    {
      $i->{ival}=$lm;
    }

    if (($i->{oid_part} == $LINKMARGH) && ($modcod==18))
    {
      $i->{ival}=$lm;
    }
  }
  return 0; 
}

# Get status for all items in one request.
# return: 0=OK, 1=error
sub get_stats
{
  my ($varbindlist,$amx)=@_;
  my ($modcod,$lm);
  my ($i,$vals);
  $vals = $session->get_request(-varbindlist => \@$varbindlist);
  if (defined $vals)
  {
    # load all catched values into record
    foreach $i (@$amx)
    {
      if (is_oid($i))
      {
        my $oid=mk_oid($i);
        my $req;
        $req=$$vals{$oid};
        $i->{ival}=$req;

        if ($i->{id} >=0)
        {
          if ($i->{oid_part} eq $LINKMARG)
          {
            $lm=$i->{ival};
          }
          if ($i->{oid_part} eq $MODCOD)
          {
            $modcod=$i->{ival};
          }
        }
      }
    }

    # determine in catched link margin was low or high and put into right space
    foreach $i (@$amx)
    {
      if (($i->{oid_part} eq $LINKMARGL) && ($modcod==12))
      {
        $i->{ival}=$lm;
      }

      if (($i->{oid_part} eq $LINKMARGH) && ($modcod==18))
      {
        $i->{ival}=$lm;
      }
    }
  }
  else
  {
    return 1;
  }
  return 0;
}

sub set_ctrl
{
  my ($oid,$val)=@_;
  my ($result,$err);
  printf("oid=$oid\n");
  
  $result = $session->get_request($oid);
  $err=$session->error();
  printf("error=$err\n");
  printf("res=${$result}{$oid}\n");


  $result = $session->set_request(-varbindlist  => ["${oid}",INTEGER,"$val"]);
  $err=$session->error();
  printf("$err\n");
}

# Display new status of all items
my $counter="0";
sub proc_stats
{
  my $am1;
  my ($am)=@_;

  showerr(sprintf("%s","xx"));
  foreach $am1 (@$am)
  {
    if ($am1->{oid_part} == $TUNERSTAT)
    { 
      if ($am1->{ival} == 0)  { $am1->{sval} = "locked"; }
      elsif ($am1->{ival}==1) { $am1->{sval} = "unlocked"; }
      else { $am1->sval="error"; }
      $am1->{ifs}=2;
    }
    elsif ($am1->{oid_part} == $SNR)
    { 
      $am1->{fval}=($am1->{ival})/10.; $am1->{ifs}=1; $am1->{sval}=sprintf("%.1f",$am1->{fval});
    }
    elsif ($am1->{oid_part} == $POWERLEVEL)
    {
      $am1->{fval}=($am1->{ival})/10.; $am1->{ifs}=1; $am1->{sval}=sprintf("%.1f",$am1->{fval});
    }
    elsif ($am1->{oid_part} == $MODCOD)
    {
      if ($am1->{ival}==12) { $am1->{sval}="8psk_3_5"; }
      elsif ($am1->{ival}==18) { $am1->{sval}="16apsk_2_3"; }
      else { $am1->{sval}=""; }
      $am1->{ifs}=2;
    }
    elsif ($am1->{oid_part} == $LINKMARG)
    {
      $am1->{fval}=$am1->{ival}/10.; $am1->{ifs}=1; $am1->{sval}=sprintf("%.1f",$am1->{fval});
    }
    elsif ($am1->{oid_part} == $LINKMARGL)
    {
      $am1->{fval}=$am1->{ival}/10.; $am1->{ifs}=1; $am1->{sval}=sprintf("%.1f",$am1->{fval});
    }
    elsif ($am1->{oid_part} == $LINKMARGH)
    {
      $am1->{fval}=$am1->{ival}/10.; $am1->{ifs}=1; $am1->{sval}=sprintf("%.1f",$am1->{fval});
    }
    elsif ($am1->{oid_part} == $INFO)
    {
      $counter=$counter+1;
      showerr(sprintf("%d",$counter));
    }
    elsif ($am1->{id} == 3)
    {
      $am1->{sval}=$am1->{ival};
    }
    elsif ($am1->{id} == 9)
    {
# bitrate changes every 3 secs; *10: seems about same as Ayecka monitor???
# bitrate_cnt: if no bitrate for 5 secs then show '0'
      if (($bitrate_pre == $am1->{ival}) && ($bitrate_cnt < 5))
      {
        $bitrate_cnt=$bitrate_cnt+1;
      }
      else
      {
        if ($bitrate_pre != 0)
        {
          my $br=($am1->{ival}- $bitrate_pre)/3000000*10;
          $am1->{sval}=sprintf("%.1f",$br);
        }
        $bitrate_pre=$am1->{ival};
        $bitrate_cnt=0;
      }
    }
    else
    {
      $am1->{ifs}=0; $am1->{sval}=sprintf("%d",$am1->{ival});
    }
  }
}

sub proc_ctrl
{
  my $am1;
  my ($am)=@_;

  showerr(sprintf("%s","xx"));
  foreach $am1 (@$am)
  {
    if ($am1->{oid_part} eq $Signal_Standard)
    { 
      if ($am1->{ival} == 0)  { $am1->{sval} = "dvbs1"; }
      elsif ($am1->{ival}==1) { $am1->{sval} = "dvbs2"; }
      elsif ($am1->{ival}==2) { $am1->{sval} = "dss"; }
      elsif ($am1->{ival}==3) { $am1->{sval} = "unknown"; }
      else { $am1->sval="error"; }
      $am1->{ifs}=2;
    }
    if ($am1->{oid_part} eq $Signal_Rate)
    {
      $am1->{sval}=sprintf("%d",$am1->{ival});
    }
    if ($am1->{oid_part} eq $Coding_Mode)
    {
    # config RX -> config set 2 -> coding mode6
      if ($am1->{ival} == 0)  { $am1->{sval} = "ccm"; }
      elsif ($am1->{ival}==1) { $am1->{sval} = "vcm"; }
      elsif ($am1->{ival}==2) { $am1->{sval} = "acm"; }
      else { $am1->sval="error"; }
      $am1->{ifs}=2;
    }
  }
}

# Display error message
sub showerr
{
  my $mess=($_=shift);
  my $am1;
  my @am=@amb;
  foreach $am1 (@am)
  {
    if ($am1->{oid_part} == $INFO)
    {
      $am1->{sval}=$mess;
    }
  }
}

# Get one time status via SNMP and display result.
sub catchstat_onetime
{
  my $res="1";
  $res=get_stats(\@varbindlista,\@ama);
  if ($res == 0)
  {
    proc_stats(\@ama);
  }
  else
  {
    my $ip=$session->hostname;
    showerr(sprintf("%s","ERROR: A No contact with $ip"));
  }
}

sub catchctrl_onetime
{
  my $res="1";
  $res=get_stats(\@varbindlistc,\@amc);
  if ($res == 0)
  {
    proc_ctrl(\@amc);
  }
  else
  {
    my $ip=$session->hostname;
    showerr(sprintf("%s","ERROR: B No contact with $ip"));
  }
}

sub catchstat
{
  my $res="1";
  if ($use_singleSNMP == 0)
  {
    $res=get_stats(\@varbindlistb,\@amb);
  }
  else
  {
    $res=get_stats_1by1();
  }
  if ($res == 0)
  {
    proc_stats(\@amb);
  }
  else
  {
    my $ip=$session->hostname;
    showerr(sprintf("%s","ERROR: C No contact with $ip"));
  }
}


#switch on/off big SNR
my $mw;
my $big;
my $extra;
my $onoffbig=0;
my $onoffextra=0;
sub dobig
{
  if ($onoffbig == 0)
  {
    $big->packForget;
  }
  else
  {
    $big->pack;
  }
  $mw->geometry(undef);
  $mw->update;
  $onoffbig = ! $onoffbig;
}

sub doextra
{
  if ($onoffextra == 0)
  {
    $extra->packForget;
  }
  else
  {
    $extra->pack;
  }
  $mw->geometry(undef);
  $mw->update;
  $onoffextra = ! $onoffextra;
}


##################################################################################
# start main; get arg. if present
my $ip=$def_ip;
my $snr_size=$def_snrsize;
my $srate=$def_srate;

# Get command line arguments
while (defined ($_=shift))
{
  if ($_ eq "-h")
  {
    printf("Options:\n");
    printf("  -ip <ip_nr> set ip nr. (def.: $ip)\n");
    printf("  -bs <size > set size of big SNR (def.: $snr_size)\n");
    printf("  -sr <sample_rate> sample rate in msec (def.: $srate)\n");
    exit;
  }
  if ($_ eq "-ip")
  {
    $_=shift;
    $ip=$_;
  }
  elsif ($_ eq "-bs")
  {
    $_=shift;
    $snr_size=$_;
  }
  elsif ($_ eq "-sr")
  {
    $_=shift;
    $srate=$_;
  }
}

# Check on valid IP
if (!defined $ip || $ip !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)
{
  showerr(sprintf("%s","Invalid or missing IP $ip"));
}
else
{
  $session = snmp_sess_init($ip);   
}

@ama=load_cmds_info();
@amb=load_cmds_status();
@amc=load_cmds_control();
@varbindlista=create_snmplist(\@ama);
@varbindlistb=create_snmplist(\@amb);
@varbindlistc=create_snmplist(\@amc);

# Start the gui
$mw = MainWindow->new;
my $i;
my $row=0;
my $wdgt;


# count # rows needed
foreach $i (@ama,@amb)
{
  if ($i->{oid_part} != $LINKMARG)
  {
    $row=$row+1;
  }
}
$row=$row+1;

#define and fill status-item table
my $tablea=$mw->Table(-rows => $row,-columns => 2,-scrollbars=>'x');
my $tableb=$mw->Table(-rows => $row,-columns => 2,-scrollbars=>'x');
my $tablec=$mw->Table(-rows => $row,-columns => 2,-scrollbars=>'x');

# active if 'version' checked
$row=0;
foreach $i (@ama)
{
  if ($i->{oid_part} != $LINKMARG)
  {
    $wdgt=$tablea->Label(-text => $i->{name},-background => 'grey',-relief => 'groove',-anchor => 'w')->pack();
    $tablea->put($row,0,$wdgt);
    $wdgt=$tablea->Label(-textvariable => \$i->{sval},-background => 'white',-relief => 'groove',-anchor => 'w')->pack();
    $tablea->put($row,1,$wdgt);

    $row=$row+1;
  }
}

#control, add to same col as tablea
foreach $i (@amc)
{
  $wdgt=$tablea->Label(-text => $i->{name},-background => 'grey',-relief => 'groove',-anchor => 'w')->pack();
  $tablea->put($row,0,$wdgt);
  $wdgt=$tablea->Label(-textvariable => \$i->{sval},-background => 'white',-relief => 'groove',-anchor => 'w')->pack();
  $tablea->put($row,1,$wdgt);

  $row=$row+1;
}

# always active: status
$row=0;
foreach $i (@amb)
{
  if ($i->{oid_part} != $LINKMARG)
  {
    $wdgt=$tableb->Label(-text => $i->{name},-background => 'grey',-relief => 'groove',-anchor => 'w')->pack();
    $tableb->put($row,0,$wdgt);
    $wdgt=$tableb->Label(-textvariable => \$i->{sval},-background => 'white',-relief => 'groove',-anchor => 'w')->pack();
    $tableb->put($row,1,$wdgt);

    $row=$row+1;
  }
}

#add buttons
$wdgt=$tableb->Checkbutton(-text => "Big $bigitemname",-command => \&dobig)->pack();
$tableb->put($row,0,$wdgt);
$wdgt=$tableb->Checkbutton(-text => "Version",-command => \&doextra)->pack();
$tableb->put($row,1,$wdgt);

$tableb->pack(-side=>'left',-anchor => 'n');

#big SNR switch
foreach $i (@amb)
{
  if ($i->{oid_part} == $bigitem)
  {
    $big=$mw->Label(-textvariable => \$i->{sval},-background => 'white',-relief => 'groove',-font => [-size=>$snr_size])->pack(-side=>'right',-anchor => 'n');
  }
}

$extra=$tablea;

doextra();
dobig();
# do first time, to give time to show error message
if (defined $session)
{
  catchstat_onetime();
  catchctrl_onetime();
  $mw->repeat($srate,sub{catchstat();});
}
else
{
  showerr(sprintf("%s","Invalid or missing IP $ip"));
}

MainLoop;

