#!/usr/bin/perl -w
use strict;
use IO::Socket; 
use ATNF::MoniCA;
use Getopt::Long;

use constant PORT => 5025;
use constant VLBILO => '202.9.11.249';
use constant MONSERVER => 'localhost';

use constant XLO => 7100;
use constant SAMPLER => 288;

use constant NONE => 0;
use constant STATUS => 1;
use constant RESET => 2;
use constant POWER => 3;
use constant LO => 4;
use constant XFREQ => 5;
use constant LFREQ => 6;
use constant RFON => 7;
use constant RFOFF => 8;
use constant HELP => 9;

# *IDN?
# *RST

sub send_command ($);
sub send_query ($);
sub setlo ($$);

my $debug = 0;
my $status = 0;
my $reset = 0;
my $rfon = 0;
my $rfoff = 0;
my $help = 0;
my $power = undef;
my $lo = undef;
my $xfreq = undef;
my $lfreq = undef;

my $mode = NONE;

GetOptions('status'=>\$status, 'reset'=>\$reset, 'power=f'=>\$power,
	   'lo=f'=>\$lo, 'xfreq=f'=>\$xfreq, 'lfreq=f'=>\$lfreq,
	   'rfon'=>\$rfon, 'rfoff'=>\$rfoff, 'debug'=>\$debug,
	   'help'=>\$help);

if ($help) {
  $mode = HELP;
} elsif ($status) {
  $mode = STATUS;
} elsif ($reset) {
  $mode = RESET;
} elsif (defined $lo) {
  $mode = LO;
} elsif (defined $xfreq) {
  $mode = XFREQ;
} elsif (defined $lfreq) {
  $mode = LFREQ;
} elsif (defined $power) {
  $mode = POWER;
} elsif ($rfon) {
    $mode = RFON;
} elsif ($rfoff) {
    $mode = RFOFF;
}

if ($mode==NONE || $mode==HELP) {
  print<<EOF;
Usage: locontrol.pl <command>

Where command one of 

  -status       Print current status of synthesiser
  -reset        Reset some values
  -power <P>    Set rf power to P dBm
  -lo <L>       Set synth LO to L MHz
  -xfreq <F>    Set syth LO to give F MHz on sky (for 8 GHz receiver)
  -lfreq <F>    Set syth LO to give F MHz on sky (for 1 GHz receiver)
  -rfon         Turn rf power on
  -rfoff        Turn rf power off
  -debug        Echo commands sent to screen
EOF

}

my $sock = new IO::Socket::INET (PeerAddr => VLBILO,
				 PeerPort => PORT,
				 Proto => 'tcp');

die "Could not create socket: $!\n" unless $sock;

my $ret;

if ($mode==STATUS) {
  $ret = send_query(":FREQ?");
  printf "LO = %.2f MHz\n", $ret/1e6;

  $ret = send_query(":POW?");
  printf "  %.1f dBm\n", $ret;

  $ret = send_query(":OUTP?");
  chomp($ret);
  if ($ret) {
    print "RF is ON\n";
  } else {
    print "RF is OFF\n";
  }

  while (1) {
    $ret = send_query(":SYST:ERR?");
    printf "Error:  %s", $ret;
    last if ($ret =~ /No error/);
  }

} elsif ($mode==RESET) {
  send_command("*CLS");
  send_command(":FREQ:REF:STAT OFF");
  send_command(":FREQ:MODE CW");


} elsif ($mode==RFON) {
  send_command(":OUTP ON");

} elsif ($mode==RFOFF) {
  send_command(":OUTP OFF");

} elsif ($mode==POWER) {
  send_command(":POW $power");
  $ret = send_query(":POW?");
  printf "Power now %.1f dBm\n", $ret;

} elsif ($mode==LO) {
  setlo($lo, undef);

} elsif ($mode==XFREQ) {
  printf("\nRequested X-band sky freq %s MHz\n", $xfreq);

  $lo = $xfreq - XLO - SAMPLER;
  printf("Setting LO to %.3f MHz (%s-%s-%s)\n", $lo, $xfreq, XLO, SAMPLER);

  setlo($lo, $xfreq);

  printf("\nAll LOs are low - band is  NOT interved\n\n");

} elsif ($mode==LFREQ) {
  printf("\nRequested L-band sky freq %s MHz\n", $lfreq);

  my $lowLO;
  my $filter;
  if ($lfreq<1500) {
    $lowLO = '-';
    $lo = $lfreq - SAMPLER;
    warn "WARNING: $lfreq below filter cut off 1130 MHz\n" if ($lfreq<1130);

    if ($lfreq<1280) {
      $filter = "Waring: Wideband filter required";
    } elsif ($lfreq<1418) {
      $filter = "Consider narrowband filter";
    } elsif ($lfreq<1460) {
      $filter = "Warning: Narrowband filter recommended to avoid alias at end of band\n";
    } else {
      $filter = "Warning: Wideband filter required, band will be aliased at edge\n";
    }
  } else {
    $lowLO = '+';
    $lo = $lfreq + SAMPLER;

    if ($lfreq<1542) {
      $filter = "Warning: Wideband filter required, band aliased at edge";
    } else  {
      $filter = "Warning: Wideband filter required";
    }
  }

  printf("Setting LO to %.3f MHz (%s%s%s)\n", $lo, $lfreq, $lowLO, SAMPLER);
  printf("%s\n", $filter);

  if ($lowLO eq '+') {
    printf("LO is High - band is inverted\n\n");
  } else {
    printf("LO is Low - band is NOT inverted\n\n");
  }

  setlo($lo, $lfreq);

  if ($lowLO eq '+') {
    printf("LO is High - band is inverted\n\n");
  } else {
    printf("LO is Low - band is NOT inverted\n\n");
  }

}

close($sock);

sub send_query ($) {
  my $cmd = shift @_;

  print $sock "$cmd\n";
  print  "SENDING $cmd\n" if ($debug);
  return <$sock>;
}

sub purge_errors {
  while (1) {
    $ret = send_query(":SYST:ERR?");
    last if ($ret =~ /No error/);
    printf "Existing Error:  %s", $ret;
  }
}

sub check_errors {
  while (1) {
    $ret = send_query(":SYST:ERR?");
    last if ($ret =~ /No error/);
    printf "Error:  %s", $ret;
  }
}

sub send_command ($) {
  my $cmd = shift @_;

  purge_errors();
  print $sock "$cmd\n";
  print  "SENDING $cmd\n" if ($debug);
  check_errors();
}

sub setlo ($$) {
  my ($lo, $freq) = @_;
  my $mon = monconnect(MONSERVER);
  warn "Could not connect to MoniCA host \"".MONSERVER."\"\n" if (!defined $mon);
  my @setpoints;
  push @setpoints, new MonSetPoint({point => 'mro.mro.vlbi.lo',
				    val => $lo,
				    type => 'flt'});
  if (defined $freq) {
    push @setpoints, new MonSetPoint({point => 'mro.mro.vlbi.freq',
				      val => $freq,
				      type => 'flt'});
  }

  if (defined $mon) {
    my $ret = monset($mon, 'vlbiscript', 'iblv', @setpoints);
    if (!$ret->success) {
      warn "Failed to set MoniCA point\n";
    }
  }

  $lo *= 1e6;
  send_command(":FREQ $lo");
  $ret = send_query(":FREQ?");
  printf "LO is now %.3f MHz\n", $ret/1e6;

}
