package RtFC;
use strict;

BEGIN {
  use Exporter ();
  use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK @EXPORT_FAIL );
  $VERSION = '0.8';
  @ISA = qw(Exporter);
  
  @EXPORT      = qw( OBSPORT UIPORT CORRPORT CORRINTERFACEPORT
		     RtFC_COMMAND_SIZE CORRCONFIGPATH_SIZE
		     OBSGRAB_COMMAND ANTENNA_NAME_COMMAND
		     ANTENNA_ID_COMMAND ERROR_COMMAND REDEFINE_COMMAND
		     TRANSFER_COMMAND DATA_RECEIVED_COMMAND RTFC_MESSAGE
		     OBSCON_COMMAND CORRGRAB_COMMAND BASE_COMMAND
		     DUPLICATE_CONNECTION SHOWOBS_COMMAND
		     ENABLEOBS_COMMAND DISABLEOBS_COMMAND PING
		     DATA_TRANSFER 
		     CORR_CONNECTION OBSDATA
		     MAXCHANNELS RCP LCP
		     make_command
		     make_field make_commandfield make_simplecommandfield
		     recv_command mask2chan readheaders
		   );
  @EXPORT_OK   = qw ($RtFC_COMMAND_SIZE);
  @EXPORT_FAIL = qw ($imsg);

  use Carp;
}

use constant DEBUG => 0;

use constant OBSPORT => 7426;
use constant UIPORT => 7423;
use constant CORRPORT => 7420;
use constant CORRINTERFACEPORT => 8524;

use constant RtFC_COMMAND_SIZE => 256;
use constant CORRCONFIGPATH_SIZE => 256;

use constant MAXCHANNELS => 8;
use constant RCP => -1;
use constant LCP => -2;

my $imsg = 0;
use constant BASE_COMMAND => $imsg++;
use constant OBSGRAB_COMMAND => $imsg++;
use constant ANTENNA_NAME_COMMAND =>$imsg++;
use constant ANTENNA_ID_COMMAND => $imsg++;
use constant ERROR_COMMAND => $imsg++;
use constant REDEFINE_COMMAND => $imsg++;
use constant TRANSFER_COMMAND => $imsg++;
use constant DATA_RECEIVED_COMMAND => $imsg++;
use constant SHOWOBS_COMMAND => $imsg++;
use constant ENABLEOBS_COMMAND => $imsg++;
use constant DISABLEOBS_COMMAND => $imsg++;
use constant RTFC_MESSAGE => $imsg++;
use constant OBSCON_COMMAND => $imsg++;
use constant CORRGRAB_COMMAND => $imsg++;
use constant PING => $imsg++;

# Error values
use constant DUPLICATE_CONNECTION => 1;

# Possible Redefine values
use constant CORR_CONECTION => 1;
use constant OBSDATA => 2;

# Possible block of data to transfer
use constant DATA_TRANSFER => 1;

sub make_command (@) {
  my $command_code = shift;

  if ($command_code==OBSGRAB_COMMAND) {
    return new RtFC::Command::ObsGrab(@_);
  } elsif ($command_code==ANTENNA_NAME_COMMAND) {
    return new RtFC::Command::Antenna_Name(@_);
  } elsif ($command_code==ANTENNA_ID_COMMAND) {
    return new RtFC::Command::Antenna_ID(@_);
  } elsif ($command_code==ERROR_COMMAND) {
    return new RtFC::Command::Error(@_);
  } elsif ($command_code==REDEFINE_COMMAND) {
    return new RtFC::Command::Redefine(@_);
  } elsif ($command_code==TRANSFER_COMMAND) {
    return new RtFC::Command::Transfer(@_);
  } elsif ($command_code==DATA_RECEIVED_COMMAND) {
    return new RtFC::Command::Data_Received(@_);
  } elsif ($command_code==SHOWOBS_COMMAND) {
    return new RtFC::Command::Showobs();
  } elsif ($command_code==PING) {
    return new RtFC::Command::Ping();
  } elsif ($command_code==ENABLEOBS_COMMAND) {
    return new RtFC::Command::Enableobs(@_);
  } elsif ($command_code==DISABLEOBS_COMMAND) {
    return new RtFC::Command::Disableobs(@_);
  } elsif ($command_code==RTFC_MESSAGE) {
    return new RtFC::Command::Message(@_);
  } elsif ($command_code==OBSCON_COMMAND) {
    return new RtFC::Command::Obscon(@_);
  } elsif ($command_code==CORRGRAB_COMMAND) {
    return new RtFC::Command::Corrgrab(@_);
  } else {
    carp "Unsupported command type ($command_code) at ";
    return undef;
  }
}

sub make_field ($$) {
  my ($subname, $field) = @_;
  my ($package, $filename, $line) = caller();

  my $sub = ("package $package;
              sub $subname {
                my \$self = shift;

		if (\@_) {
		  \$self->{$field} = shift;
		}
		return \$self->{$field};
              }");
  eval $sub;
}

sub make_commandfield ($$) {
  my ($subname, $index) = @_;
  my ($package, $filename, $line) = caller();

  my $sub = ("package $package;
              sub $subname {
                my \$self = shift;

		if (\@_) {
		  \$self->value->[$index] = shift;
		}
		return \$self->value->[$index];
              }");
  eval $sub;
}

sub make_simplecommandfield ($) {
  my ($subname) = @_;
  my ($package, $filename, $line) = caller();

  my $sub = ("package $package;
              sub $subname {
                my \$self = shift;

		if (\@_) {
		  \$self->value = shift;
		}
		return \$self->value;
			   }");
  eval $sub;
}

sub mask2chan ($) {
  my $chan = shift;

  my @chans = ();
  my $c = 1;
  while ($chan) {
    push @chans, $c if ($chan & 0x1);
    $c++;
    $chan >>=1;
  }
  return @chans;
}

sub readheaders ($) {
  my $file = shift;

  my %headers = ();

  open(FILE, $file) || croak "Could not open $file: $!\n";
  while (<FILE>) {
    last if (/^END/);
    if (/^NCHAN\s+(\S+)/) {
      $headers{NCHAN} = $1;
    } elsif (/^TIME\s+(\S+)/) {
      $headers{TIME} = $1;
    }
  }
  close(FILE) || die "Could not close $file: $!\n";
  return(%headers);
}


# Message format
# 
# OBSGRAB_COMMAND
#  Code         int     Code associated with this specific request to grab data
#  NewCorr      char    0 or 1 depending if this is a grab or recorr command
#  MJD          double  MJD of start of integration
#  Integration  float   Amount of data (seconds) to copy and correlate
#  Npoint       integer FFT size
#  Channels     short   Bitmask of channels to grab. 0 is all
#  secoffset    char    Offset in seconds
#  Obs          char[2] Observatory ID
#  mode         char[32] Mark5 mode (or "LBA")
#
# DATA_RECEIVED_COMMAND
#     Command used by obs.pl child to tell parent that all the data has been
#     collected and is ready to correlate
#  code         int     Correlation identification code
#  mjd          float   MJD at start of data
#  dir          string  Path to where the baseband data is stored
#  file         string  Filename of basebande data
#
#
# OBSCON_COMMAND
#     Summary of currently connected commands
# Array of
#  Code         string  2 character antenna code
#  Name         string  Antenna name (max 20 char transmitted)
#  enabled      byte    1 if antenna is enabled fringe checking or not
#
#
# CORRGRAB_COMMAND  ** OUTDATE**!!!!
#     Specific parameters to use for next correlation and info needed to create
#     grab command for observatories
#  Code         int     Code associated with this specific request to grab data
#  Newcorr      byte    1 if "grab" command, 0 if "recorr" command
#  MJD          double  MJD of start of integration
#  Integration  float   Amount of data (seconds) to copy and correlate
#  npoint       int    Number of spectral points
#  pack         nbyte  bit encoding type
#  nant         byte   Number of entries in next array
#  Array of
#   Chan        byte   Channel number to grab
#  nant         byte   Number of entries in next array
#  Array of
#   Ant ID       string 2 character antenna code
#   offset       float  Antenna delay offset in usec
#  nant          byte   Number of entries in next array
#  Array of
#   Ant ID       string 2 character antenna code
#   rate         float  Antenna rate in usec/sec (**check unit**)

sub recv_data ($$$$$$) {
  my ($sock, $size, $type, $sel, $killedsock, $i) = @_;

  my $buf;
  my $status = $sock->recv($buf, $size);

  if (! defined $status) {
    warn "Error reading $type socket\n";
    return undef;
  } elsif (length $buf == 0) {
    # Socket must have closed
    print "Remote $type socket closed\n";
    $sel->remove($sock) if (defined $sel);
    $sock->shutdown(2);
    $_[0] = undef; # Set $sock to undef
    if (defined $i) {
      unshift @{$killedsock}, $i; # Store largest index first
    }
    return undef;
  } else {
    return $buf;
  }
}

sub recv_command ($$$;$$) {
  my ($sock, $sel, $type, $i, $killedsock) = @_;

   print "** Receiving command from $type\n" if (DEBUG);

  my $buf = recv_data($sock, 1+4, $type, $sel, $killedsock, $i);
  return undef if (! defined $buf);

  my ($cmd_type,$size) = unpack 'CN', $buf;

  $size-= 1+4;

  my $cmd = make_command($cmd_type);
  return undef if ! defined $cmd;
  print "**   type $cmd_type  " if (DEBUG);
  print $cmd->name, "\n" if (DEBUG);

  if ($size>0) {
    $buf = recv_data($sock, $size, $type, $sel, $killedsock, $i);
    return $buf if (!defined $buf);

    $cmd->command_unpack($buf);
  }

  return $cmd;

}

package RtFC::ObsLink;

use RtFC;

sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;

  my $self = {OBS_SOCKET => shift,
	      OBS_DATASOCKET => undef,
	      OBS_IP => undef,
	      OBS_NAME => undef,
	      OBS_CODE => undef,
	      OBS_PID => undef,
	      OBS_ENABLED => 1
	     };
  bless ($self, $class);

  return $self;
}

make_field('socket', 'OBS_SOCKET');
make_field('datasocket', 'OBS_DATASOCKET');
make_field('ip', 'OBS_IP');
make_field('name', 'OBS_NAME');
make_field('code', 'OBS_CODE');
make_field('pid', 'OBS_PID');
make_field('enabled', 'OBS_ENABLED');

sub disable {
  my $self = shift;
  $self->enabled(0);
}

sub enable {
  my $self = shift;
  $self->enabled(1);
}

package RtFC::Correlation;

use Carp;
use RtFC;

sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;

  my $code = shift;
  my $mjd = shift;
  my $int = shift;
  my $mode = shift;
  my $nchan = shift;
  my $pack = shift;

  my $offsets = shift;
  my $clockrates = shift;
  my $obs = shift;

  my %offsets = ();
  if (defined $offsets) {
    while (my ($key,$value) = each %{$offsets}) {
      $offsets{$key} = $value;
    }
  }

  my %clockrates = ();
  if (defined $clockrates) {
    while (my ($key,$value) = each %{$clockrates}) {
      $clockrates{$key} = $value;
    }
  }

  my %obsdata = ();
  if (defined $obs) {
    foreach (@$obs) {
      $obsdata{$_} = undef;
    }
  } 

  my $self = {CORR_CODE => $code,
	      MJD => $mjd,
	      INT => $int,
	      MODE => $mode,
	      NCHAN => $nchan,
	      PACK => $pack,
	      OFFSETS => \%offsets,
	      CLOCKRATES => \%clockrates,
	      CORR_OBS => \%obsdata,
	     };
  bless ($self, $class);

  return $self;
}

make_field('code', 'CORR_CODE');
make_field('mjd', 'MJD');
make_field('integration', 'INT');
make_field('mode', 'MODE');
make_field('nchan', 'NCHAN');
make_field('pack', 'PACK');
make_field('offsets', 'OFFSETS');
make_field('clockrates', 'CLOCKRATES');
make_field('obs', 'CORR_OBS');

package RtFC::Command;
use Carp;
use RtFC;

use constant DEBUG => 0;

sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;

  my $self  = {
	       VALUE => undef
	      };
  bless ($self, $class);

  $self->setvals(@_);
  
  return $self;
}

sub setvals {
  my $self = shift;

  my $simple = $self->simple;
  if ($simple==2) {
    # Nothing to do
  } elsif ($simple) {
    $self->value(shift);
  } else {
    $self->value([@_]);
  }
}

make_field('value', 'VALUE');

sub type { return BASE_COMMAND }
sub name { return 'Base Command type'; }
sub size { return 0; }
sub simple { return 0; }
sub template { return ''; }

sub send {
  my $self = shift;
  my $sock = shift;
  my $where = shift;

  my $buf = $self->command_pack();

  printf("Sending command %s\n", $self->name) if (DEBUG);

  my $sent = $sock->send($buf);
  if (!defined $sent) {
    carp "Error sending message to $where\n";
    return 0;
  } elsif ($sent!=length($buf)) {
    carp "Only sent $sent bytes!!\n";
    return undef;
  }
  return 1;
}

# Tricky
# OBSCON_COMMAND
# ANTENNA_NAME - string with size
# RTFC_MESSAGE - string
# DATA_RECEIVED_COMMAND
# CORRGRAB_COMMAND

sub command_pack {
  my $self = shift;

  my $simple = $self->simple;
  my $template = 'CN'.$self->template;
  my $size = 1+4+$self->size;

  #print "SIZE=$size\n";
  #print "SELF=$self\n";
  #print "TEMPLATE=$template\n";
  #print "TYPE=", $self->type, "\n";
  #print "VALUE=", $self->value, "\n" if ($simple==1);
  #print "VALUE=", join('*',@{$self->value}), "\n" if ($simple==0);

  if ($simple==2) {
    return pack $template, $self->type, $size;
  } elsif ($simple) {
    return pack $template, $self->type, $size, $self->value;
  } else {
    return pack $template, $self->type, $size, @{$self->value};
  }
}

sub command_unpack {
  my $self = shift;
  my $buf = shift;

  if (!defined $buf) {
    carp "unpack: undefined value ";
    return undef;
  }

  my $template = $self->template;
  my @vals = unpack $template, $buf;

  $self->setvals(@vals);
}

package RtFC::Command::ObsGrab;
use Carp;
use RtFC;
use vars qw(@ISA);

use constant DEBUG => 0;

@ISA = ("RtFC::Command");

#  Code         int     Code associated with this specific request to grab data
#  MJD          double  MJD of start of integration
#  Integration  float   Amount of data (seconds) to copy and correlate
#  Channels     short   Bitmask of channels to grab. 0 is all
#  secoffset    char    Offset in seconds
#  Obs          char[2] Observatory ID
#  mode         char[32] Mark5 mode (or "LBA")
# 

sub type { return OBSGRAB_COMMAND }
sub name { return 'ObsGrab' }
sub size { return 4+8+4+2+1+2+32 }
sub simple { return 0 }
sub template { return 'NdfscA2Z32' }

make_commandfield('code', 0);
make_commandfield('mjd', 1);
make_commandfield('integration', 2);
make_commandfield('channels', 3);
make_commandfield('secoffset', 4);
make_commandfield('antid', 5);
make_commandfield('mode', 6);

package RtFC::Command::Obscon;
use Carp;
use RtFC;

use vars qw(@ISA);
@ISA = ("RtFC::Command");

sub type { return OBSCON_COMMAND }
sub name { return 'Obscon' }
sub size { return 1 }
sub simple { return 0 }
sub template { return 'C' }

sub command_pack {
  my $self = shift;
  
  my $template = 'CN'.$self->template;
  my $size = 1+4+$self->size;

  my $nobs = scalar(@{$self->value});
  if ($nobs>255) {
    croak sprintf("Too many (%d) antennas connected. Max is 255", $nobs);
  }

  $size += (3+21+1)*$nobs;
  my $buf = pack $template, $self->type, $size, $nobs;

  foreach (@{$self->value}) {
    $buf .= pack 'Z3Z21C', $_->[0], $_->[1], $_->[2];
  }

  return $buf;
}

sub command_unpack {
  my $self = shift;
  my $value = shift;

  if (!defined $value) {
    carp "unpack: undefined value ";
    return undef;
  }

  my $template = $self->template;
  my $nobs = unpack $template, $value;

  my @obssum;
  if ($nobs>0) {
    for (my $i=0; $i<$nobs; $i++) {
      $template = sprintf('x%dZ3Z21C', $self->size+$i*(21+3+1));
      push @obssum, [unpack $template, $value];
    }
  }
  $self->setvals(@obssum);
}

package RtFC::Command::Error;
use RtFC;
use Carp;

use vars qw(@ISA);
@ISA = ("RtFC::Command");

sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;

  my $self  = {
	       VALUE => shift
	      };
  bless ($self, $class);

  return $self;
}

sub type { return ERROR_COMMAND }
sub name { return 'Error' }
sub size { return 1 }
sub simple { return 1 }
sub template { return 'C' }

make_simplecommandfield('error');

package RtFC::Command::Showobs;
use Carp;
use RtFC;

use vars qw(@ISA);
@ISA = ("RtFC::Command");

sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;

  my $self  = {};
  bless ($self, $class);

  return $self;
}

sub type { return SHOWOBS_COMMAND }
sub name { return 'Show Observatories' }
sub simple { return 2 }

package RtFC::Command::Ping;
use Carp;
use RtFC;

use vars qw(@ISA);
@ISA = ("RtFC::Command");

sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;

  my $self  = {};
  bless ($self, $class);

  return $self;
}

sub type { return PING }
sub name { return 'Ping' }
sub simple { return 2 }

package RtFC::Command::Corrgrab;
use Carp;
use RtFC;

use vars qw(@ISA);
@ISA = ("RtFC::Command");

sub type { return CORRGRAB_COMMAND }
sub name { return 'Corrgrab' }
sub size { return 4+1+8+4+4+1 } # Code, NewCorr, MJD, Integration, npoint, pack
sub simple { return 0 }
sub template { return 'NCdfNC' }

make_commandfield('code', 0);
make_commandfield('newcorr', 1);
make_commandfield('mjd', 2);
make_commandfield('integration', 3);
make_commandfield('npoint', 4);
make_commandfield('pack', 5);
make_commandfield('vex', 6);
make_commandfield('postfix', 7);
make_commandfield('offsets', 8);
make_commandfield('clockrates', 9);
make_commandfield('secoffsets', 10);
make_commandfield('chans', 11);
make_commandfield('observatories', 12);
make_commandfield('obsfiles', 13);  # Not transfered

sub command_pack {
  my $self = shift;
  
  my $template = 'CN'.$self->template;
  my $size = 1+4+$self->size;

  my $vexname = $self->vex;
  my $vexsize = 0;
  $vexsize = length($vexname) if ((defined $vexname) && $vexname);
  $size += 2+$vexsize;

  my $postfix = $self->postfix;
  my $postfixsize = 0;
  $postfixsize = length($postfix) if ((defined $postfix) && $postfix);
  $size += 2+$postfixsize;

  my $noffsets = scalar(keys(%{$self->offsets}));
  if ($noffsets>255) {
    croak sprintf("Too many (%d) antenna offsets. Max is 255", $noffsets);
  }
  $size += $noffsets*(2+4)+1;

  my $nrates = scalar(keys(%{$self->clockrates}));
  if ($nrates>255) {
    croak sprintf("Too many (%d) antenna rates. Max is 255", $nrates);
  }
  $size += $nrates*(2+4)+1;

  my $nsecoffsets = scalar(keys(%{$self->secoffsets}));
  if ($nsecoffsets>255) {
    croak sprintf("Too many (%d) antenna sec offsets. Max is 255", $nsecoffsets);
  }
  $size += $nsecoffsets*(2+1)+1;

  my $nchans = scalar(keys(%{$self->chans}));
  if ($nchans>15) {
    croak sprintf("Too many (%d) antenna channels selected. Max is 15", $nchans);
  }
  $size += $nchans*(2+2)+1;

  my @obs = ();
  if (defined $self->observatories) {
    @obs = @{$self->observatories};
  }
  my $nobs = scalar(@obs);
  $size += $nobs*2+1;

  my $buf = pack $template, $self->type, $size, @{$self->value}[0..5];

  # Vexname
  $buf .= pack 'n', $vexsize;
  $buf .= pack "A$vexsize", $vexname if ($vexsize>0);

  # Postfix
  $buf .= pack 'n', $postfixsize;
  $buf .= pack "A$postfixsize", $postfix if ($postfixsize>0);

  # Offsets
  $buf .= pack 'C', $noffsets;
  while (my ($key, $value) = each %{$self->offsets}) {
    $buf .= pack 'a2f', $key, $value;
  }

  # Rates
  $buf .= pack 'C', $nrates;
  while (my ($key, $value) = each %{$self->clockrates}) {
    $buf .= pack 'a2f', $key, $value;
  }

  # Secoffsets
  $buf .= pack 'C', $nsecoffsets;
  while (my ($key, $value) = each %{$self->secoffsets}) {
    $buf .= pack 'a2c', $key, $value;
  }

  # ??
  $buf .= pack 'C', $nchans;
  while (my ($key, $value) = each %{$self->chans}) {
    $buf .= pack 'a2s', $key, $value;
  }

  # Antenna IDs
  $buf .= pack 'C', $nobs;
  foreach (@obs) {
    $buf .= pack 'A2', $_;
  }

  return $buf;
}

sub command_unpack {
  my $self = shift;
  my $buf = shift;

  if (!defined $buf) {
    carp "unpack: undefined value ";
    return undef;
  }

  my $template = $self->template;

  my $size = $self->size;

  my @vals = unpack $template, $buf;

  # Vexname
  my $vexname = undef;
  $template = sprintf('x%dn', $size);
  my $vexsize = unpack $template, $buf;
  $size += 2;
  if ($vexsize>0) {
    $template = sprintf('x%dA%d', $size, $vexsize);
    $vexname = unpack $template, $buf;
    $size += $vexsize;
  }

  # Postfix
  my $postfix = undef;
  $template = sprintf('x%dn', $size);
  my $postfixsize = unpack $template, $buf;
  $size += 2;
  if ($postfixsize>0) {
    $template = sprintf('x%dA%d', $size, $postfixsize);
    $postfix = unpack $template, $buf;
    $size += $postfixsize;
  }

  # Offsets
  $template = sprintf('x%dC', $size);
  my $nant = unpack $template, $buf;
  $size += 1;
  my %offsets = ();
  if ($nant>0) {
    for (my $i=0; $i<$nant; $i++) {
      $template = sprintf('x%da2f', $size);
      my ($ant, $off) = unpack $template, $buf;

      $offsets{$ant} = $off;
      $size += (2+4);
    }
  }

  # Rates
  $template = sprintf('x%dC', $size);
  $nant = unpack $template, $buf;
  $size += 1;

  my %clockrates = ();

  if ($nant>0) {
    for (my $i=0; $i<$nant; $i++) {
      $template = sprintf('x%da2f', $size);
      my ($ant, $rate) = unpack $template, $buf;
      $clockrates{$ant} = $rate;
      $size += (2+4);
    }
  }

  # Sec Offset
  $template = sprintf('x%dC', $size);
  $nant = unpack $template, $buf;
  $size += 1;
  my %secoffsets = ();
  if ($nant>0) {
    for (my $i=0; $i<$nant; $i++) {
      $template = sprintf('x%da2c', $size);
      my ($ant, $soff) = unpack $template, $buf;
      $secoffsets{$ant} = $soff;
      $size += (2+1);
    }
  }

  $template = sprintf('x%dC', $size);
  $nant = unpack $template, $buf;
  $size += 1;
  my %channels = ();
  if ($nant>0) {
    for (my $i=0; $i<$nant; $i++) {
      $template = sprintf('x%da2s', $size);
      my ($ant, $chan) = unpack $template, $buf;
      $channels{$ant} = $chan;
      $size += (2+2);
    }
  }

  $template = sprintf('x%dC', $size);
  my $nobs = unpack $template, $buf;
  $size += 1;
  my @obs = ();
  if ($nobs>0) {
    for (my $i=0; $i<$nobs; $i++) {
      $template = sprintf('x%dA2', $size);
      push @obs, unpack $template, $buf;
      $size += 2;
    }
  }

  $self->setvals(@vals, $vexname, $postfix, \%offsets, \%clockrates, \%secoffsets, 
		 \%channels, \@obs);
}

package RtFC::Command::Data_Received;
use Carp;
use RtFC;

use vars qw(@ISA);
@ISA = ("RtFC::Command");

sub type { return DATA_RECEIVED_COMMAND }
sub name { return 'Data Received' }
sub size { return 4+8+256+21+4 }
sub simple { return 0 }
sub template { return 'NdZ256Z21s' }

make_commandfield('code', 0);
make_commandfield('mjd', 1);
make_commandfield('dir', 2);
make_commandfield('file', 3);
make_commandfield('channels', 4);

package RtFC::Command::Antenna_Name;
use Carp;
use RtFC;

use vars qw(@ISA);
@ISA = ("RtFC::Command");

sub type { return ANTENNA_NAME_COMMAND }
sub name { return 'Antenna Name' }
sub size { return 80 }
sub simple { return 1 }
sub template { return 'Z80' }

make_simplecommandfield('antenna_name');

package RtFC::Command::Antenna_ID;
use Carp;
use RtFC;

use vars qw(@ISA);
@ISA = ("RtFC::Command");

sub type { return ANTENNA_ID_COMMAND }
sub name { return 'Antenna ID' }
sub size { return 3 }
sub simple { return 1 }
sub template { return 'Z3' } # Why not A2??

make_simplecommandfield('antenna_id');

package RtFC::Command::Enableobs;
use Carp;
use RtFC;

use vars qw(@ISA);
@ISA = ("RtFC::Command");

sub type { return ENABLEOBS_COMMAND }
sub name { return 'Enable Obs' }
sub size { return 2 }
sub simple { return 1 }
sub template { return 'A2' }

make_simplecommandfield('antenna_id');

package RtFC::Command::Disableobs;
use Carp;
use RtFC;

use vars qw(@ISA);
@ISA = ("RtFC::Command");

sub type { return DISABLEOBS_COMMAND }
sub name { return 'Disable Obs' }
sub size { return 2 }
sub simple { return 1 }
sub template { return 'A2' }

make_simplecommandfield('antenna_id');

package RtFC::Command::Transfer;
use Carp;
use RtFC;

use vars qw(@ISA);
@ISA = ("RtFC::Command");

sub type { return TRANSFER_COMMAND }
sub name { return 'Transfer' }
sub size { return 1+4+8+2+4 }
sub simple { return 0 }
sub template { return 'CNdsN' }

make_commandfield('transfer_type', 0);
make_commandfield('code', 1);
make_commandfield('mjd',  2);
make_commandfield('channels', 3);
make_commandfield('datasize', 4);

package RtFC::Command::Redefine;
use Carp;
use RtFC;

use vars qw(@ISA);
@ISA = ("RtFC::Command");

sub type { return REDEFINE_COMMAND }
sub name { return 'Redefine' }
sub size { return 1 }
sub simple { return 1 }
sub template { return 'C' }

make_simplecommandfield('redef');

1;

