mirror of
				https://github.com/Telecominfraproject/wlan-lanforge-scripts.git
				synced 2025-10-31 02:38:03 +00:00 
			
		
		
		
	 72712ff548
			
		
	
	72712ff548
	
	
	
		
			
			These scripts will now be publicly available in a git repo for easier shared development and change tracking.
		
			
				
	
	
		
			365 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			365 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/perl
 | |
| ##
 | |
| ## Reads a CSV of attenuator settings and plays them back 
 | |
| ## Remember that 300 is deci-dB; eg 300: sets a channel to 30.0 dB
 | |
| ##
 | |
| use strict;
 | |
| use warnings;
 | |
| use diagnostics;
 | |
| use Carp;
 | |
| $SIG{__DIE__} = sub{Carp::confess(@_)};
 | |
| use Getopt::Long;
 | |
| use Net::Telnet;
 | |
| use Time::HiRes qw(usleep);
 | |
| use LANforge::Utils;
 | |
| use LANforge::csv qw();
 | |
| $| = 1;
 | |
| 
 | |
| our $usage = qq($0: replay a csv file of attenuator values
 | |
|    --mgr|m           LANforge manager host
 | |
|    --file|f          CSV file
 | |
|    --delay|d         Override of %delay variable, milliseconds between applying rows
 | |
|    --loop|l          Repeat indefinitely
 | |
|    --channel|c       Override of channels variable, eg: 1.2.3.1,2.3.4.3
 | |
|    --minimum|min|i   Set minimum attenuation value (not lower than zero)
 | |
|    --maximum|max|x   Set maximum attenuation value (not higher than 955)
 | |
|    --dry_run|dryrun|dry|n    Do not apply attenuation, just parse file, ignore nap times
 | |
| 
 | |
| Example that works on localhost manager:
 | |
|    $0 --file values.csv
 | |
| 
 | |
| Example that overrides delay to 1600, overrides channels and runs once:
 | |
|    $0 --mgr 192.168.101.1 --file values.csv --delay 1600  --channel 1.1.3.1,1.1.3.2,1.1.3.3
 | |
| 
 | |
| Example that overrides delay to 600ms, loops forever, and overrides min and max attenuation
 | |
|    $0 -m 192.168.101.1 -f values.csv -d 600 -l -min 10 -max 900
 | |
| 
 | |
| File Format:
 | |
|    # < comment lines are ignored
 | |
|    # 60 milliseconds between rows
 | |
|    delay,60
 | |
|    # Directives: DELAY,delay and naptime are equivalent
 | |
|    # Sets minimum and maximum attenuation for all channels
 | |
|    min,10
 | |
|    max,900
 | |
|    # Directives: MINIMUM,MAXIMUM,MIN,MAX,minimum,min,maximum and max are allowed
 | |
| 
 | |
|    #  The next line defines column B as attenuator channel 1.1.13.1
 | |
|    #  and column C as attenuator channel 2.1.25.1. Remember that
 | |
|    #  attennuator channels are values (shelf).(resource).(serialno).(channel)
 | |
|    #  and channels are presently values {1, 2, 3, 4}.
 | |
|    channels,1.1.13.1,2.1.25.1
 | |
|    # Directives: CHANNELS,channels are equivalent
 | |
| 
 | |
|    # Attenuation values are in deci-dBm, resolution of 5ddB:
 | |
|    # The next line sets 1.1.13.1 to 36.5dB, 2.1.25.1 to 30.0dB:
 | |
|    attenuate,365,300
 | |
|    # Directives: ATTENUATE,attenuate, "", and _ are equivalent.
 | |
|    
 | |
|    # The next line leaves 1.1.13.1 alone, sets 2.1.25.1 to 31.0dB,
 | |
|    # _ is an abbreviation for attenuate
 | |
|    _,NA,+10
 | |
|    # The next line leaves 1.1.13.1 alone, sets 2.1.25.1 to 30.5dB,
 | |
|    # Blank first column is an abbreviation for attenuate
 | |
|    ,NA,-5
 | |
|    
 | |
|    # Only some basic CSV formulas are interpretable, and only operate
 | |
|    # on the previous values of the attenuator; the next line sets
 | |
|    # sets 1.1.13.1 to 36.0dB, sets 2.1.25.1 to 31.0dB
 | |
|    ,=B6-5,=C6+5
 | |
|    
 | |
|    # does nothing for a period
 | |
|    _,_,NA,,
 | |
|    
 | |
|    # does nothing for 35ms
 | |
|    sleep,35
 | |
|    # Directives: SLEEP,sleep, and nap are equivalent
 | |
| );
 | |
| 
 | |
| 
 | |
| our $csvfile         = undef;
 | |
| our $delay           = -1;
 | |
| our $delay_override  = -1;
 | |
| our $do_loop         = 0;
 | |
| our @channels        = (); # in order list of channels
 | |
| our %last_atten      = (); # a map of last-known values
 | |
| our $channel_override= undef;
 | |
| our $quiet           = "yes";
 | |
| our $line            = 0; # line number
 | |
| our $lfmgr_host      = "localhost";
 | |
| our $lfmgr_port      = 4001;
 | |
| our $dryrun          = 0;
 | |
| our $min_atten       = 0;
 | |
| our $max_atten       = 995;
 | |
| 
 | |
| GetOptions (
 | |
|    'manager|mgr|m=s'    => \$::lfmgr_host,
 | |
|    'mgr_port|port|p=i'  => \$::lfmgr_port,
 | |
|    'file|f=s'           => \$::csvfile,
 | |
|    'delay|d=i'          => \$::delay_override,
 | |
|    'loop|l'             => \$::do_loop,
 | |
|    'channels|c'         => \$::channel_override,
 | |
|    'quiet|q=s'          => \$::quiet,
 | |
|    'dry_run|dry|n'      => \$::dryrun,
 | |
|    'minimum|min|mn|i=i' => \$::min_atten,
 | |
|    'maximum|max|mx|x=i' => \$::max_atten,
 | |
| ) || die("$::usage");
 | |
| 
 | |
| die("Please specify a manager address;\n$::usage") 
 | |
|    if (!defined $::lfmgr_host || "$::lfmgr_host" eq "");
 | |
| 
 | |
| die("Please specify a csv file;\n$::usage")
 | |
|    if (!defined $::csvfile || "$::csvfile" eq "");
 | |
| 
 | |
| die("Unable to find csv file: $::csvfile")
 | |
|    unless(-f $::csvfile );
 | |
| 
 | |
| our $cfile=new LANforge::csv();
 | |
| $::cfile->readFile($::csvfile);
 | |
| 
 | |
| if ($::cfile->numRows < 1) {
 | |
|    die( "empty file, nothing to do");
 | |
| }
 | |
| 
 | |
| if ($::quiet eq "1" ) {
 | |
|    $::quiet = "yes";
 | |
| }
 | |
| elsif ($::quiet eq "0" ) {
 | |
|    $::quiet = "no";
 | |
| }
 | |
| 
 | |
| if (defined $::channel_override && "$::channel_override" != "") {
 | |
|    for my $c ( split(/,/, $::channel_override)) {
 | |
|       push(@::channels, $c);
 | |
|       $::last_atten{$c} = 0;
 | |
|    }
 | |
| }
 | |
| 
 | |
| die("Minimum attenuation must be between [0-954]")
 | |
|    if ($::min_atten > 994 || $::min_atten < 0);
 | |
| die("Maximum attenuation must be between [1-995]")
 | |
|    if ($::max_atten > 995 || $::max_atten < 1);
 | |
| die("Minimum attenuation must be less than maximum attenuation")
 | |
|    if ($::max_atten <= $::min_atten);
 | |
| 
 | |
| sub lastAtten {
 | |
|    my $arg = shift;
 | |
|    die ("lastAtten: called without argument") 
 | |
|       if (! defined $arg || "$arg" eq "");
 | |
|    if ($arg =~ /^\d+$/) {
 | |
|       if (!defined($::channels[$arg])) {
 | |
|          warn "Channels: ".join(', ', @::channels);
 | |
|          die ("no channel recorded at position $arg");
 | |
|       }
 | |
|       die ("no channel [$::channels[$arg]]")
 | |
|          if (!defined $::last_atten{$::channels[$arg]});
 | |
| 
 | |
|       return $::last_atten{$::channels[$arg]};
 | |
|    }
 | |
|    elsif ($arg =~ /^\d+\.\d+\.\d+\.\d+$/) {
 | |
|       die ("no channel [$::channels[$arg]]")
 | |
|          if (!defined $::last_atten{$::channels[$arg]});
 | |
| 
 | |
|       return $::last_atten{$arg};
 | |
|    }
 | |
|    die ("lastAtten: What is channel $arg?");
 | |
| }
 | |
| 
 | |
| sub attenuate {
 | |
|    my $channel = shift;
 | |
|    my $value   = shift;
 | |
| 
 | |
|    die("attenuate: no line number") 
 | |
|       if (!defined $::line || "$::line" eq "");
 | |
|    die("attenuate: $::line: no channel") 
 | |
|       if (!defined $channel || "$channel" eq "");
 | |
| 
 | |
|    return if (!defined $value || "$value" eq "");
 | |
|    return if (lc($value) =~ /^(na|_)$/);
 | |
|    return if (lc($value) =~ /^\s*[!;\#]/);
 | |
| 
 | |
|    my ($shelf, $resource, $serno, $chan) = split(/\./, $channel);
 | |
|    #print "shelf:$shelf, r:$resource, ser:$serno, ch:$chan\n";
 | |
|    die( "[$::line] attenuate: shelf misconfigured:[$channel][$value]")
 | |
|       if ($shelf != 1);
 | |
| 
 | |
|    die( "[$::line] attenuate: resource misconfigured:[$channel][$value]")
 | |
|       if ($resource < 1);
 | |
| 
 | |
|    die( "[$::line] attenuate: serial number misconfigured:[$channel][$value]")
 | |
|       if ($serno < 1);
 | |
| 
 | |
|    die( "[$::line] attenuate: channel misconfigured:[$channel][$value]")
 | |
|       if ($chan < 0 || $chan > 4);
 | |
|   
 | |
|    my $prev_value = $::last_atten{$channel};
 | |
|    if ($value =~ /^[-+]/) {
 | |
|       die("[$::line] attenuate: no previous value set for $channel")
 | |
|          if (! defined $prev_value);
 | |
| 
 | |
|       $value = $prev_value + (0+$value);
 | |
|       #warn "VALUE MATH[$value] ";
 | |
|    }
 | |
| 
 | |
|    if ($value > $::max_atten)  {
 | |
|       warn("[$::line] attenuate: value cannot be higher than $::max_atten")
 | |
|          unless($::quiet eq "yes");
 | |
|       $value = $::max_atten;
 | |
|    }
 | |
| 
 | |
|    if ($value < $::min_atten) {
 | |
|       warn("[$::line] attenuate: value cannot be lower than $::min_atten")
 | |
|          unless($::quiet eq "yes");
 | |
|       $value = $::min_atten;
 | |
|    }
 | |
| 
 | |
|    $::last_atten{$channel} = $value;
 | |
|    $::utils->doAsyncCmd("set_atten $shelf $resource $serno $chan $value")
 | |
|       unless (defined $::dryrun && $::dryrun);
 | |
| 
 | |
|    print "$::line: set_atten $shelf.$resource.$serno.$chan $value\n"
 | |
|       if ($::quiet ne "yes" || $::dryrun);
 | |
| }
 | |
| ##
 | |
| ##    M A I N
 | |
| ##
 | |
| 
 | |
| # connect to manager
 | |
| 
 | |
| our $t = new Net::Telnet(Prompt  => '/default\@btbits\>\>/',
 | |
|                          Timeout => 60);
 | |
| $t->open(Host    => $::lfmgr_host,
 | |
|          Port    => $::lfmgr_port,
 | |
|          Timeout => 10);
 | |
| $t->waitfor("/btbits\>\>/");
 | |
| 
 | |
| our $utils = new LANforge::Utils();
 | |
| $::utils->telnet($t);         # Set our telnet object.
 | |
| if ($::quiet eq "yes") {
 | |
|   $::utils->cli_send_silent(1); # Do show input to CLI
 | |
|   $::utils->cli_rcv_silent(1);  # Repress output from CLI ??
 | |
| }
 | |
| else {
 | |
|   $::utils->cli_send_silent(0); # Do show input to CLI
 | |
|   $::utils->cli_rcv_silent(0);  # Repress output from CLI ??
 | |
| }
 | |
| 
 | |
| 
 | |
| if (defined $::delay_override && $::delay_override != -1 && $::delay_override < 1000) {
 | |
|    warn("$0: --delay is in milliseconds, values less than 1000 (1 second) might be meaningless");
 | |
|    sleep 2;
 | |
| }
 | |
| die ("$0: --delay of zero or less is not permitted.")
 | |
|    if (defined $::delay_override && $::delay_override != -1 && $::delay_override <= 0);
 | |
| 
 | |
| $::delay = $::delay_override if (defined $::delay_override && $::delay_override > 0);
 | |
| 
 | |
| my $loop_count = 0;
 | |
| while ($loop_count == 0 || $::do_loop) {
 | |
|    $loop_count++;
 | |
|    for (my $rownum = 0; $rownum < $::cfile->numRows(); $rownum++) {
 | |
|       $::line     = $rownum+1;
 | |
|       my $ra_row  = $::cfile->getRow($rownum);
 | |
|       
 | |
|       next if (@{$ra_row} == 0); # empty row
 | |
| 
 | |
|       if (lc($ra_row->[0]) =~ /^(delay|naptime)$/) {
 | |
|          next if (defined $::delay_override && $::delay_override != -1);
 | |
| 
 | |
|          $::delay = 0 + $ra_row->[1];
 | |
|          die ("$line: delay of zero or less is not permitted")
 | |
|             if ($::delay <= 0);
 | |
|          next;
 | |
|       }
 | |
| 
 | |
|       if (lc($ra_row->[0]) =~  /^channels$/ && (!defined $::channel_override)) {
 | |
|          my @tempchannels = @$ra_row;
 | |
|          shift @tempchannels;
 | |
|          %::last_atten= ();
 | |
|          for my $c (@tempchannels) {
 | |
|             push(@::channels, $c);
 | |
|             $::last_atten{$c} = -1;
 | |
|          }
 | |
|          next;
 | |
|       }
 | |
| 
 | |
|       if (lc($ra_row->[0]) =~ /^(sleep|nap)$/) {
 | |
|          if (!defined $ra_row->[1] || (0 + $ra_row->[1]) < 1) {
 | |
|             die("$line: sleep value needs to be 1ms or greater");
 | |
|          }
 | |
|          usleep($ra_row->[1] *1000) unless ($::dryrun);
 | |
|          next;
 | |
|       }
 | |
| 
 | |
|       if (lc($ra_row->[0]) =~ /^(attenuate|_)$/ || $ra_row->[0] eq "") {
 | |
|          #print "\n";
 | |
|          my $col        = 1;
 | |
|          foreach my $ch (@::channels) {
 | |
|             my $value   = "NA";
 | |
|             my $data    = $::cfile->getCell($col, $rownum, "na");
 | |
|             #print "DATA($col,$::line)[$data] ";
 | |
| 
 | |
|             if (!defined $data || "$data" eq "" ) { 
 | |
|                $col++;
 | |
|                next;
 | |
|             }
 | |
|             if (lc($data) =~ /^(na|_)$/ || $data =~ /^\s*\#.*$/) {
 | |
|                #warn ("skipping data[$data] at $col,$::line");
 | |
|                $col++;
 | |
|                next;
 | |
|             }
 | |
|             if ($data =~ /^\d+$/) {
 | |
|                $value   = 0 + $data;
 | |
|             }
 | |
|             elsif ($data =~ /^=[B-Z]\d+[+-]\d+$/i) { # we have a formula
 | |
|                my ($acol,$arow,$delta) = $data =~ /^=([B-Z])(\d+)([+-]\d+)$/i;
 | |
|                $acol    = ord(uc($acol)) - 65;
 | |
|                my $pval = $::cfile->getCell($acol, $arow-1, 0);
 | |
|                if (!defined $pval) {
 | |
|                   $pval = lastAtten($col-1);# $::last_atten{$::channels[$col]};
 | |
|                   warn("Failed to find valid references at cell[$col,$::line], using previous attenuation:".$pval);
 | |
|                }
 | |
|                if ( $pval !~ /^\d+$/) {
 | |
|                   $value = lastAtten($col-1);# $::last_atten{$::channels[$col]};
 | |
|                   die("Failed to find valid references at cell[$col,$::line]:".$value)
 | |
|                      if ( ! defined $value);
 | |
| 
 | |
|                   #$value = $value + (0+$delta);
 | |
|                   warn "Substituting [$value]: cell[$col,$::line] refers to cell[$acol,$arow] with non absolute value:$pval";
 | |
|                }
 | |
|                else {
 | |
|                   $value   = $pval + (0 + $delta);
 | |
|                }
 | |
|                #print "acol[$acol] arow[$arow] delta[$delta] pval[$pval] value[$value]\n";
 | |
|             }
 | |
|             elsif ($data =~ /^\@?[+]+\d+$/ ) { # add relative
 | |
|                my ($delta) = $data =~ /^\@?[+]+(\d+)$/;
 | |
|                my $pval    = lastAtten($col-1); #$::last_atten{$::channels[$col]};
 | |
|                $value      = $pval + (0 + $delta);
 | |
|             }
 | |
|             elsif ( $data =~ /^\@?[-]+\d+$/ ) { # subtract relative
 | |
|                my ($delta) = $data =~ /^\@?[-]+(\d+)$/;
 | |
|                my $pval    = lastAtten($col-1); #$::last_atten{$::channels[$col]};
 | |
|                $value      = $pval + (-1 * (0 + $delta));
 | |
|             }
 | |
|             else {
 | |
|                warn "Unknown directive[$data] ";
 | |
|                $col++;
 | |
|                next;
 | |
|             }
 | |
|             attenuate($ch, "$value");
 | |
|             $col++;
 | |
|          }
 | |
| 
 | |
|          die("Step delay not set correctly[$::delay]") 
 | |
|             if (!defined $::delay || "$::delay" eq "" || (0+$::delay) < 1);
 | |
| 
 | |
|          usleep($::delay * 1000) unless ($::dryrun);
 | |
|          next
 | |
|       }
 | |
|       die("$::line: unknown directive[".$ra_row->[0]);
 | |
|    }
 | |
| }
 | |
| 
 | |
| ## eof
 |