/* -------------------------------------------------------------------------- */
/* -                   Astronomical Telescope Control                       - */
/* -                          XmTel XPA Server                              - */
/* -                                                                        - */
/* -------------------------------------------------------------------------- */
/*                                                                            */
/* Copyright (c) 2014 John Kielkopf                                           */
/* kielkopf@louisville.edu                                                    */
/*                                                                            */
/* This file is part of XmTel.                                                */
/*                                                                            */
/* -------------------------------------------------------------------------- */
/*                                                                            */
/* This program is based on stest.c distributed with xpa version 2.1.5        */
/* XPA and stest are                                                          */
/* Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory              */
/*                                                                            */
/* -------------------------------------------------------------------------- */
/*                                                                            */
/* May 5, 2014                                                                */
/*   Version: 1.0                                                             */
/*     From stest.c in xpa distribution 2.1.5                                 */
/*     From tel.c and xmtel.c in xmtel distribution 6.0                       */
/*                                                                            */
/* -------------------------------------------------------------------------- */

/* Dependencies from xmtel */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <dirent.h>
#include <errno.h>
#include <math.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

#include "xpatel.h"
#include "protocol.h"
         


/* Dependencies on external XmTel routines */

/* protocol.c */
/* pointing.c */
/* algorithms.c */

/* Dependencies from xpa */

#define HAVE_STRING_H 1
#define HAVE_MALLOC_H 1
#define HAVE_STDLIB_H 1
#define HAVE_UNISTD_H 1
#define HAVE_SETJMP_H 1
#include "xpap.h"

#define MAX_FPS 10

extern char *optarg;
extern int optind;

XPA xpa1;
int  xpa_quiet=0;
int n=0;
size_t  save_bytes=-1;
char *save_buf=NULL;

char *mode="";
char name[SZ_LINE];
char xclass[SZ_LINE];


/* Files */

FILE *fp_config;                      /* Configuration file pointer */
static char *configfile;              /* Configuration file name */
void read_config(void);               /* Configuration file reader */
void write_coords(double ra, double dec);    /* Writes ra and dec to status */


/* ------------------------------------------------------------- */
/*                                                               */
/* External routines                                             */
/*                                                               */
/* Hardware-dependent external routines defined in the protocols */
/* Called by the server  to control the telescope                */
/*                                                               */
/* ------------------------------------------------------------- */
 
/* Interface control */

extern void ConnectTel(void);         
extern void DisconnectTel(void);
extern int  CheckConnectTel(void);

/* Slew and track control */

extern void SetRate(int newRate);
extern void StartSlew(int direction);
extern void StopSlew(int direction);
extern void StartTrack(void);
extern void CenterGuide(double centerra, double centerdec, 
  int raflag, int decflag, int pmodel);
extern void StopTrack(void);
extern void FullStop(void);

/* Celestial coordinate read, write, and go to */

extern void GetTel(double *telra, double *teldec, int pmodel);
extern int  GoToCoords(double newRA, double newDec, int pmodel);
extern int  CheckGoTo(double desRA, double desDec, int pmodel);

/* Corrections for proper motion, precession, aberration, and nutation */

extern void Apparent(double *ra, double *dec, int dirflag);  
extern void PrecessToEOD(double epoch, double  *ra, double  *dec);
extern void PrecessToEpoch(double epoch, double  *ra, double  *dec);
extern void ProperMotion(double epoch, double *ra, double *dec, 
  double pm_ra, double pm_dec); 
extern void TestAlgorithms(void);

/* Time from the computer system processed by the algorithms package */

extern double LSTNow(void);
extern double UTNow(void);

/* Utility */

extern double Map12(double ha);
extern double Map24(double ra);
extern double Map180(double dec);


/* ----------------------------------- */
/* ---- End of external routines  ---- */
/* ----------------------------------- */

/* Convert string deg:min:sec to double */

int dmstod (char *instr, double *datap);

/* Convert dms double to string deg:min:sec */

void dtodms (char *outstr, double *dmsp); 


/* Management of telescope                    */

void inittel(void);
void telescope(void);
void fetch_telescope_coordinates(); 
void write_coords (double ra, double dec);

/* Telescope variables */

double telha, telra, teldec;   /* telescope ha, ra and dec at eod */
double targetra, targetdec;    /* target ra and dec at eod */

double offsetha = 0.;
double offsetdec = 0.;
double offsetha_default = 0.;
double offsetdec_default = 0.;
double polaraz = 0.;
double polaralt = 0.;
double arcsecperpix = ARCSECPERPIX;
double modelha0 = 0.;
double modelha1 = 0.;
double modeldec0 = 0.;
double modeldec1 = 0.;
double modelha1_default = 0.;
double modeldec1_default = 0.;


/* Telescope flags */

int pmodel = RAW;                    /* pointing model default to raw data */
int telspd = FIND;                   /* Drive speed */
int teldir = EAST;                   /* Drive direction */                        
int telflag = FALSE;                 /* Telescope connection flag */
int gotoflag = FALSE;                /* Goto progress flag */
int homeflag = FALSE;                /* Home request state flag */
int parkflag = FALSE;                /* Park request state flag */
int trackflag = FALSE;               /* Tracking state flag */

/* Center guide control */

int guidedecflag = 1;                /* Flag to control dec guide function */
int guideraflag = 1;                 /* Flag to control ra  guide function */
int guideflag = 0;                   /* Flag to control center guide */
double guidera;                      /* Guiding center ra and dec */ 
double guidedec;                     /* Guiding center ra and dec */ 
  
/* Site */

double SiteLatitude = LATITUDE;        /* Latitude in degrees + north */  
double SiteLongitude = LONGITUDE;      /* Longitude in degrees + west */  
double SiteAltitude = ALTITUDE;        /* Altitude in meters */
double SitePressure = PRESSURE;        /* Atmospheric pressure in Torr */
double SiteTemperature = TEMPERATURE ; /* Local atmospheric temperature in C */

/* Mount */

int  telmount = GEM;                   /* One of GEM, EQFORK, ALTAZ */
double nowut, nowlst;                  /* Used for global current times */
double homeha = HOMEHA;                /* Startup HA */
double homedec = HOMEDEC;              /* Startup Dec */
double parkha = PARKHA;                /* Park telescope at this HA */
double parkdec = PARKDEC;              /* Park telescope at this Dec */
char   telserial[32];                  /* Serial port if needed */

/* Files */

int fd_fifo_in, fd_fifo_out;           /* FIFO file descriptors */
FILE *fp_config;
static char *configfile;               /* Configuration name */



/* Prototypes for xpatel callbacks  */

int send_status_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_status_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);

int send_track_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_track_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);

int send_goto_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_goto_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);

int send_guide_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_guide_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);

int send_target_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_target_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);

int send_telescope_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_telescope_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);

int send_speed_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_speed_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);

int send_move_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_move_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);

int send_refract_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_refract_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);

int send_dynamic_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_dynamic_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);
    
int send_offset_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_offset_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);
      
int send_polar_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_polar_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);
  
int send_park_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_park_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);
  
 int send_home_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len);

int receive_home_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len);
 
  
  
  

/* Main program */

int main (int argc, char **argv)
{

  char tbuf[SZ_LINE];
  char cmd[SZ_LINE];
  int c;
  int delay=0;

  /* Process switch arguments */
  /* Telescope xpaserver would normally be started without arguments */
  
  /* Arguments recognized are: */
  
  /*   d int -- sets delay int seconds after starting bkgd cmd */
  /*   f cmd -- starts cmd in background */
  /*   q  -- runs quietly */
   
  
  *cmd = '\0';
  while ((c = getopt(argc, argv, "d:f:q")) != -1)
  {
    switch(c)
    {
    case 'd':
      delay = atoi(optarg);
      break;
    case 'f':
      snprintf(cmd, SZ_LINE, "%s %s &\n", argv[0], optarg);
      break;
    case 'q':
      xpa_quiet = TRUE;
      break;
    }
  }

  /* Initialize the telescope */
  
  inittel();

  /* Prepare to start the xpatel server */

  if( optind >= argc )
  {
    strcpy(name, "tel");
  }
  else
  {
    strcpy(name, argv[optind]);
  }
  
  strcpy(xclass, name);
  cluc(xclass);

  /* Telescope commands through xpa */
    
  /* Create the class tel */
  
  snprintf(tbuf, SZ_LINE, "%s", name);
  xpa1 = XPACmdNew(xclass, tbuf);
  if( xpa1 == NULL )
  {
    fprintf(stderr, "Could not start tel on xpa \n");
  }
  else
  {

    /* Add commands with their callbacks to tel */
    
    XPACmdAdd(xpa1, "status", "on/off/exit",
      send_status_cb, (void *)"status", mode, 
      receive_status_cb, (void *)"status", mode);

    XPACmdAdd(xpa1, "track", "track on/off",
      send_track_cb, (void *)"track", mode, 
      receive_track_cb, (void *)"track", mode);

    XPACmdAdd(xpa1, "goto", "goto on/off",
      send_goto_cb, (void *)"goto", mode, 
      receive_goto_cb, (void *)"goto", mode);

    XPACmdAdd(xpa1, "guide", "guide on/off",
      send_guide_cb, (void *)"guide", mode, 
      receive_guide_cb, (void *)"guide", mode);

    XPACmdAdd(xpa1, "target", "target ra dec (J2000)",
      send_target_cb, (void *)"target", mode, 
      receive_target_cb, (void *)"target", mode);

    XPACmdAdd(xpa1, "telescope", "telescope ra dec (J2000)",
      send_telescope_cb, (void *)"telescope", mode, 
      receive_telescope_cb, (void *)"telescope", mode);

    XPACmdAdd(xpa1, "speed", "speed slew/find/center/guide",
      send_speed_cb, (void *)"speed", mode, 
      receive_speed_cb, (void *)"speed", mode);

    XPACmdAdd(xpa1, "move", "move dir time/pix (seconds except in guide mode)",
      send_move_cb, (void *)"move", mode, 
      receive_move_cb, (void *)"move", mode);

    XPACmdAdd(xpa1, "refract", "refract on/off",
      send_refract_cb, (void *)"refract", mode, 
      receive_refract_cb, (void *)"refract", mode);

    XPACmdAdd(xpa1, "dynamic", "dynamic on/off [harate decrate (pix/sec)]",
      send_dynamic_cb, (void *)"dynamic", mode, 
      receive_dynamic_cb, (void *)"dynamic", mode);

    XPACmdAdd(xpa1, "offset", "offset on/off/target/clear [ha (hr) dec (deg)]",
      send_offset_cb, (void *)"offset", mode, 
      receive_offset_cb, (void *)"offset", mode);

    XPACmdAdd(xpa1, "polar", "polar on/off/clear [azm (deg) alt(deg)]",
      send_polar_cb, (void *)"polar", mode, 
      receive_polar_cb, (void *)"polar", mode);

    XPACmdAdd(xpa1, "park", "park on/off",
      send_park_cb, (void *)"park", mode, 
      receive_park_cb, (void *)"park", mode);

    XPACmdAdd(xpa1, "home", "home on/off",
      send_home_cb, (void *)"home", mode, 
      receive_home_cb, (void *)"home", mode);


  }
    
    
  /* Start another background process if option -f cmd */
  
  if( *cmd != '\0' )
  {
    fprintf(stdout, "starting bkgd process: %s", cmd);
    system(cmd);
  }

  /* Delay if requested by option -d int  */
  
  if( delay )
  {
    fprintf(stdout, "starting delay of %d seconds before background process ...", delay);
    XPASleep(delay*1000);
    fprintf(stdout, " done\n");
  }
  
  fflush(stdout);
  fflush(stderr);


  /* Start select loop and monitor for requests */
   
  fprintf(stdout, "\nEntering telescope and xpa polling loop ...\n");
  
  /* When the telescope is ready telflag will be set TRUE */
  
  while (telflag)
  {
 
    /* Poll XPA for 250 milliseconds and process up to 1 request */
    
    XPAPoll(250,1);
    telescope();
  }
    
  XPAFree(xpa1);

  /* Cleanup and exit */
  
  XPACleanup();
  if( save_buf ) xfree(save_buf);
  exit(0);
}



/* Telescope utility functions */

/* Initialization before starting control loop */

void inittel()
{

  /* Initialization control */
  
  static int inited;
  
  if (inited)
  { 
    return;
  }
  
  /* Set initial values for control parameters */
    
  offsetha = 0.;
  offsetdec = 0.;
  polaraz = 0.;
  polaralt = 0.;
  pmodel = RAW;
  telspd = FIND;
  SetRate(telspd);
  SiteLatitude = LATITUDE;       
  SiteLongitude = LONGITUDE;     
  SiteAltitude = ALTITUDE;       
  SitePressure = PRESSURE;       
  SiteTemperature = TEMPERATURE;
  strcpy (telserial,TELSERIAL);
     
  /* Handle the configuration file */
  /* This may alter some of the defaults */
    
  read_config();
    
  /* Connect with the telescope */

  telflag=FALSE;
  
  fprintf(stderr,"Connecting to the local telescope ... \n");
  ConnectTel();
  /* telflag=CheckConnectTel();  */
  telflag = TRUE;
  if (telflag != TRUE)
  {
    fprintf(stderr,"The telescope controller is not available.");
    exit(1);
  }
                      
  /* Set flag so we do the initialization only once */
  
  inited = 1;

  return;
}



/* Write ra and dec to a system status file */

void write_coords (double ra, double dec)
{
  FILE* outfile;
  outfile = fopen("/usr/local/observatory/status/telcoords","w");
  if ( outfile == NULL )
  {
    fprintf(stderr,"Cannot update telcoords status file\n");
    return;
  }

  fprintf(outfile, "%lf %lf\n", ra, dec);      
  fclose(outfile);
}


/* Import current telescope coordinates: ra, ha, and dec */

void fetch_telescope_coordinates() 
{
  if (CheckConnectTel() != FALSE)
  {
    GetTel(&telra, &teldec, pmodel);
    telha = Map12(LSTNow() - telra);
  }
}

/* Convert string deg:min:sec or hr:min:sec to a double */

int dmstod (char *instr, double *datap)
{
  double h=0., m=0., s=0.;
  int negflag;
  int convertflag;
  
  while (isspace(*instr))
    instr++;
  if (*instr == '-') {
    negflag = 1;
    instr++;
  } else
    negflag = 0;
    
  convertflag = sscanf (instr,  "%lf%*[:]%lf%*[:]%lf", &h, &m, &s);
  if (convertflag < 1)
    return (-1);
  *datap = h + m/60. + s/3600.;
  if (negflag)
    *datap = - *datap;
  return (0);
}
    
/* Convert double to string deg:min:sec or hr:min:sec */
/* This routine has memory leaks that should be fixed */

void dtodms (char *outstr, double *dmsp)
{

  int d=0, m=0, s=0;
  int negflag;
  double dms, ms;
   
  dms = *dmsp;

  /* If negative, treat as positive and set sign in string */

  if (dms < 0 ) 
  {
    negflag = 1;
    dms = - dms;
  }
  else
  {
    negflag = 0;
  }

  /* Allow for truncation if input is in seconds of arc */
  
  dms = dms + 0.5/3600.;

  /* Get the whole part in degrees or hours, as needed */  

  d = (int) dms;
  
  /* Could test here for overflow at 24h or 360d          */
  /*   but we'll assume that's been done before the call. */
    
  ms = dms - (double) d;
  ms = ms*60.;
  m = (int) ms;
  s = (int) 60.*(ms - (double) m);
  if (negflag)
  {
    sprintf(outstr,"-%02d:%02d:%02d",d,m,s);
  }
  else
  {
    sprintf(outstr,"%02d:%02d:%02d",d,m,s);      
  }
}



/* Priority telescope operations called during the polling cycle   */

void telescope (void)
{
  
  /* Only services that run synchronously go here */
  
    
  /* Guiding? */
  
  if ( guideflag == TRUE )
  {
    CenterGuide(guidera, guidedec, guideraflag, guidedecflag, pmodel);
  }   
  

  /* In motion? */

  if ( gotoflag == TRUE )
  {
    
    if ( CheckGoTo(targetra,targetdec,pmodel) != TRUE )
    {
      gotoflag = TRUE;
    }
    else if ( homeflag == TRUE )
    { 
      gotoflag = FALSE;
      parkflag = FALSE;
      trackflag = FALSE;
      fetch_telescope_coordinates();
      write_coords(telra, teldec);
    }
    else if ( parkflag == TRUE )
    { 
      gotoflag = FALSE;
      homeflag = FALSE;
      trackflag = FALSE;
      fetch_telescope_coordinates();
      write_coords(telra, teldec);
    }    
    else
    { 
      gotoflag = FALSE;
      homeflag = FALSE;
      parkflag = FALSE;
      StartTrack();
      trackflag = TRUE;
      fetch_telescope_coordinates();
      write_coords(telra, teldec);
    }    


  } 

  
  /* Start another polling cycle */
  
  return;
}


/* Read and parse the initial configuration file */
/* Will override defaults for                    */
/*                                               */
/*   polaraz                                     */
/*   polaralt                                    */
/*   offsetha                                    */
/*   offsetdec                                   */
/*   latitude                                    */
/*   longitude                                   */
/*   altitude                                    */
/*   pressure                                    */
/*   temperature                                 */
/*   parkha                                      */
/*   parkdec                                     */
/*   telserial                                   */

void read_config(void)
{
  char configstr[121];
  char *configptr = configstr;
  int n;
      
  configfile = (char *) malloc (MAXPATHLEN);
  strcpy(configfile,CONFIGFILE);  
  fp_config = fopen(configfile, "r");
  
  if ( fp_config == NULL )
  {
    fprintf(stderr,"New telescope configuration not found.\n");
    fprintf(stderr,"Using default telescope parameters.\n");
    return;
  }
  else
  {
    fprintf(stderr,"Telescope and site parameters redefined.\n");
  }
  
  while ( configstr == fgets(configstr,80,fp_config) )
  {
    configptr = strstr(configstr,"tel.mount");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%d",&telmount);
        fprintf(stderr,"Telescope mounting type: %d\n",telmount);
      }
    }

    configptr = strstr(configstr,"tel.serial");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        strncpy(telserial,configptr,30);
        n = strlen(telserial);
        if (n>0)
        {
          telserial[n-1]='\0';
        }  
        fprintf(stderr,"Telescope serial port set to: %s\n",telserial);
      }
    }
    
    configptr = strstr(configstr,"tel.homeha");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&homeha);
        fprintf(stderr,"Home HA: %lf\n",homeha);
      }  
    }

    configptr = strstr(configstr,"tel.homedec");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&homedec);
        fprintf(stderr,"Home Dec: %lf\n",homedec);
      }  
    } 

    configptr = strstr(configstr,"tel.parkha");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&parkha);
        fprintf(stderr,"Park HA: %lf\n",parkha);
      }  
    }

    configptr = strstr(configstr,"tel.parkdec");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&parkdec);
        fprintf(stderr,"Park Dec: %lf\n",parkdec);
      }  
    }
 
    configptr = strstr(configstr,"tel.polaraz");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&polaraz);
        fprintf(stderr,"Polar azimuth: %lf\n",polaraz);
      }  
    }
    
    configptr = strstr(configstr,"tel.polaralt");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&polaralt);      
        fprintf(stderr,"Polar altitude: %lf\n",polaralt);
      }  
    } 

    configptr = strstr(configstr,"tel.offsetha");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&offsetha);
        offsetha_default = offsetha;
        fprintf(stderr,"Offset in hour angle: %lf\n",offsetha);
      }
    }
    
    configptr = strstr(configstr,"tel.offsetdec");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&offsetdec);
        offsetdec_default = offsetdec;       
        fprintf(stderr,"Offset in declination: %lf\n",offsetdec);
      }
    } 
    
    configptr = strstr(configstr,"tel.modelha1");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&modelha1_default);
        fprintf(stderr,"Default model parameter ha1: %lf\n",modelha1_default);
        modelha0 = (LSTNow() - telra);
        modelha1 = modelha1_default;
      }
    }
        
    configptr = strstr(configstr,"tel.modeldec1");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&modeldec1_default);
        fprintf(stderr,"Default model parameter dec1: %lf\n",modeldec1_default);
        modeldec0 = teldec;
        modelha0 = (LSTNow() - telra);
        modeldec1 = modeldec1_default;      
      }
    } 

    configptr = strstr(configstr,"site.longitude");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&SiteLongitude);
        fprintf(stderr,"Site longitude: %lf\n",SiteLongitude);
      }
    } 
    
    configptr = strstr(configstr,"site.latitude");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&SiteLatitude);
        fprintf(stderr,"Site latitude: %lf\n",SiteLatitude);
      }
    }

    configptr = strstr(configstr,"site.altitude");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&SiteAltitude);
        fprintf(stderr,"Site altitude: %lf\n",SiteAltitude);
      }
    } 
    
    configptr = strstr(configstr,"site.pressure");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&SitePressure);
        fprintf(stderr,"Site pressure: %lf\n",SitePressure);
      }
    } 
    
    configptr = strstr(configstr,"site.temperature");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&SiteTemperature);
        fprintf(stderr,"Site temperature: %lf\n",SiteTemperature);
      }
    } 

    configptr = strstr(configstr,"ccd.arcsecperpix");
    if ( configptr != NULL)
    {
      configptr = strstr(configstr,"=");
      if ( configptr != NULL)
      {
        configptr = configptr + 1;
        sscanf(configptr,"%lf",&arcsecperpix);
        fprintf(stderr,"CCD image scale arcsec/pixel: %lf\n",arcsecperpix);
      }
    }
  
  
  }  
  fclose(fp_config);

}

/* ------------------------------------------------------------- */
/*                                                               */
/* Command send/receive routines                                 */
/*                                                               */
/* ------------------------------------------------------------- */

int send_status_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];
  
  /* Send the requested data */
  
  if ( telflag == TRUE )
  {
    snprintf(tbuf, SZ_LINE, "%s", "on \n");
  }
  else
  {
    snprintf(tbuf, SZ_LINE, "%s", "off \n");
  }
 
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_status_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
 

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    if( !strcmp(paramlist, "exit") )
    {
      DisconnectTel();  
      telflag = FALSE;
      XPAFree(xpa1);    
      exit(0);
    }
    else if ( !strcmp(paramlist, "off") )
    {
      DisconnectTel();  
      telflag = FALSE;
    }    
    else if ( !strcmp(paramlist, "on") )
    {
      ConnectTel();  
      telflag = TRUE;    
    }    
  }
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}


int send_track_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];
  
  /* Send the requested data */
  
  if ( trackflag == TRUE )
  {
    snprintf(tbuf, SZ_LINE, "%s", "on \n");
  }
  else
  {
    snprintf(tbuf, SZ_LINE, "%s", "off \n");
  }
 
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_track_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
 

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    if( !strcmp(paramlist, "on") )
    {
      StartTrack();
      trackflag = TRUE;
     }
    else if( !strcmp(paramlist, "off") )
    {
      StopTrack();
      trackflag = FALSE;
    }
  }
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}


int send_goto_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];
  
  /* Send the requested data */
  
  if ( gotoflag == TRUE )
  {
    snprintf(tbuf, SZ_LINE, "%s", "on \n");
  }
  else
  {
    snprintf(tbuf, SZ_LINE, "%s", "off \n");
  }
 
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_goto_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
 

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    if( !strcmp(paramlist, "on") )
    {
      gotoflag=GoToCoords(targetra,targetdec,pmodel);
      return(0);
    }
    else if( !strcmp(paramlist, "off") )
    {
      FullStop();
      gotoflag = FALSE;
      return(0);
    }
  }
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}


int send_guide_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];

  
  /* Send the requested data */
  
  if ( guideflag == TRUE )
  {
    snprintf(tbuf, SZ_LINE, "%s", "on \n");
  }
  else
  {
    snprintf(tbuf, SZ_LINE, "%s", "off \n");
  }
 
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_guide_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
 

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    if( !strcmp(paramlist, "on") )
    {
      if (!gotoflag)
      {
        if (!trackflag)
        {
          StartTrack();
          trackflag = TRUE;
        }
        GetTel(&telra, &teldec, pmodel);
        telha = Map12(LSTNow() - telra);     
        guidera = telra;
        guidedec = teldec;
        modelha0 = (LSTNow() - guidera);
        modeldec0 = guidedec;
        guideflag = TRUE;
        return(0);
      }
    }
    else if( !strcmp(paramlist, "off") )
    {
      guideflag = FALSE;
      return(0);
    }
  }
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}

int send_target_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];

  double targetra2;
  double targetdec2;
  
  targetra2=targetra;
  targetdec2=targetdec;
  Apparent(&targetra2,&targetdec2,-1);
  
  
  /* Send the requested data */
  
  snprintf(tbuf, SZ_LINE, "%lf %lf %lf %lf\n", targetra2, targetdec2, targetra, targetdec);
 
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_target_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
  double targetra2;
  double targetdec2;
  int j;

  /* Set home and park requests off with a target request */
  
  homeflag = FALSE;
  parkflag = FALSE;

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    j = sscanf(paramlist,"%lf %lf", &targetra2, &targetdec2);
    if (j == 2)
    {
      targetra = targetra2;
      targetdec = targetdec2;
      Apparent(&targetra, &targetdec, 1);
    }
  }
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}

int send_telescope_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];

  double telra2;
  double teldec2;
    
  fetch_telescope_coordinates();
    
  telra2=telra;
  teldec2=teldec;
  Apparent(&telra2,&teldec2,-1);
  
  
  /* Send the requested data */
  
  snprintf(tbuf, SZ_LINE, "%lf %lf %lf %lf \n", telra2, teldec2, telra, teldec);
 
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_telescope_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
 

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    
    /* Direct external input of coordinates not permitted */

  }
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}

int send_speed_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];
  
  /* Send the requested data */
  
  if ( telspd == SLEW )
  {
    snprintf(tbuf, SZ_LINE, "%s", "slew \n");
  }
  else if ( telspd == FIND )
  {
    snprintf(tbuf, SZ_LINE, "%s", "find \n");
  }
  else if ( telspd == FIND )
  {
    snprintf(tbuf, SZ_LINE, "%s", "center \n");
  }
  else if ( telspd == FIND )
  {
    snprintf(tbuf, SZ_LINE, "%s", "guide \n");
  }
     
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_speed_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
 

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    if( !strcmp(paramlist, "slew") )
    {
      telspd = SLEW;
      SetRate(telspd);
    }
    else if( !strcmp(paramlist, "find") )
    {
      telspd = FIND;
      SetRate(telspd);
    }
    else if( !strcmp(paramlist, "center") )
    {
      telspd = CENTER;
      SetRate(telspd);
    }
    else if( !strcmp(paramlist, "guide") )
    {
      telspd = GUIDE;
      SetRate(telspd);
    }
  }
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}

int send_move_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];
  
  /* Send the requested data */
  
 
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_move_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
  char movedir[SZ_LINE];
  double ddec;
  double dha;
  double movestep;
  int j;

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    
    j=sscanf(paramlist,"%s %lf", movedir, &movestep);
    
    /* Provides direction name and a step amount */
    /* Movestep is in seconds except for guide mode where it is pixels */
    
    if (j == 2)
    {
      if( !strcmp(movedir, "north") )
      {
        if (guideflag == TRUE)
        {
          ddec =  -1.0*movestep;
          dha = 0.0*movestep;
        }
        else
        {
          teldir=NORTH;
          StartSlew(teldir);
        }
      
      }
      else if ( !strcmp(movedir, "south") )
      {
        if (guideflag == TRUE)
        {
          ddec = 1.0*movestep;
          dha = 0.0*movestep;
        }
        else
        {
          teldir=SOUTH;
          StartSlew(teldir);       
        }  
      
      
      }    
      else if ( !strcmp(movedir, "east") )
      {
        if (guideflag == TRUE)
        {
          dha = 1.0*movestep;
          ddec = 0.0*movestep;
        }
        else
        {
          teldir=EAST;
          StartSlew(teldir);
        }

      
      }
      else if ( !strcmp(movedir, "west") )
      {
        if (guideflag == TRUE)
        {
          dha =  -1.0*movestep;
          ddec = 0.0*movestep;
        }
        else
        {
          teldir=WEST;
          StartSlew(teldir);              
        }
      }
      
      if (guideflag == TRUE)
      {
              
        /* Update dynamic zero point for current guide center */
        
        modelha0 = Map12(LSTNow() - guidera);
        modeldec0 = guidedec;

        /* Change declination units from pixels to degrees */
        
        ddec = arcsecperpix*ddec/3600.;
        
        /* Add the declination correction to the permanent offsetdec in degrees */
        
        offsetdec = Map180(offsetdec + ddec);
       
        /* Change hour angle units from pixels to hours */
        
        dha = arcsecperpix*dha/54000.;

        /* Add the ha correction to the permanent offsetha in hours */

        offsetha = Map12(offsetha + dha);
                     
      }
      else
      {  
      
        /* Run for movestep seconds */
        
        usleep(movestep*1000000.);
        
        StopSlew(teldir);
        
        /* Wait for the telescope to come to rest */
        usleep(250000.*((double) telspd));
        
        /* Start tracking */
        StartTrack();

      }             
    }
  }  
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}

int send_refract_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];
  
  /* Send the requested data */
  
  if ( pmodel == (pmodel | REFRACT) )
  {
    snprintf(tbuf, SZ_LINE, "%s", "on \n");
  }
  else
  {
    snprintf(tbuf, SZ_LINE, "%s", "off \n");
  }
 
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_refract_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
 

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    if( !strcmp(paramlist, "on") )
    {
      pmodel = (pmodel | REFRACT);
    }
    else if( !strcmp(paramlist, "off") )
    {
      pmodel = (pmodel & ~(REFRACT));
    }
  }
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}


int send_dynamic_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];
  
  /* Send the requested data */
  
  if ( pmodel == (pmodel | DYNAMIC) )
  {
    snprintf(tbuf, SZ_LINE, "%s %lf %lf \n", "on",  modelha1, modeldec1);
  }
  else
  {
    snprintf(tbuf, SZ_LINE, "%s %lf %lf \n", "off", modelha1, modeldec1);
  }
   
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_dynamic_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
  double tmpha;
  double tmpdec;
  char tmpcmd[SZ_LINE]; 
  int j;

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    j=sscanf(paramlist,"%s %lf %lf", tmpcmd, &tmpha, &tmpdec);
    if ((j == 3) && (strcmp(tmpcmd,"on") == 0))
    {
      pmodel = (pmodel | DYNAMIC);
      modelha1 = tmpha;
      modeldec1 = tmpdec;
      modelha0 = (LSTNow() - telra);    
      modeldec0 = teldec;  
    }
    else if ((j == 3) && (strcmp(tmpcmd,"off") == 0))
    {
      pmodel = (pmodel & ~(DYNAMIC));
      modelha1 = tmpha;
      modeldec1 = tmpdec;
      modelha0 = (LSTNow() - telra);    
      modeldec0 = teldec;  
    }
    else if ((j == 1) && (strcmp(tmpcmd,"on") == 0))
    {
      pmodel = (pmodel | DYNAMIC);
    }
    else if ((j == 1) && (strcmp(tmpcmd,"off") == 0))
    {
      pmodel = (pmodel & ~(DYNAMIC));
    }    
  }
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}


int send_offset_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];
  
  
  /* Send the requested data */
  
  if (pmodel == (pmodel | OFFSET))
  {
    snprintf(tbuf, SZ_LINE, "%s %lf %lf \n", "on",  offsetha, offsetdec);
  }
  else
  {
    snprintf(tbuf, SZ_LINE, "%s %lf %lf \n", "off", offsetha, offsetdec);
  }
   
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_offset_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
  double tmpha;
  double tmpdec;
  char tmpcmd[SZ_LINE]; 
  int j;

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    j=sscanf(paramlist,"%s %lf %lf", tmpcmd, &tmpha, &tmpdec);
    if ((j == 3) && (strcmp(tmpcmd,"on") == 0))
    {
      if ((fabs(tmpha) <= 15.0) && (fabs(tmpdec) <= 1.0))
      {
        offsetdec = tmpdec;
        offsetha = tmpha;
        pmodel = (pmodel | OFFSET);
      }      
    }
    else if ((j == 3) && (strcmp(tmpcmd,"off") == 0))
    {
      if ((fabs(tmpha) <= 15.0) && (fabs(tmpdec) <= 1.0))
      {
        offsetdec = tmpdec;
        offsetha = tmpha;
        pmodel = (pmodel & ~(OFFSET));
      }      
    }
    else if ((j == 1) && (strcmp(tmpcmd,"on") == 0))
    {
      pmodel = (pmodel | OFFSET);
    }
    else if ((j == 1) && (strcmp(tmpcmd,"off") == 0))
    {
      pmodel = (pmodel & ~(OFFSET));      
    }
    else if ((j == 1) && (strcmp(tmpcmd,"target") == 0))
    {
      tmpdec = targetdec - teldec; 
      tmpha =  Map12(telra - targetra);  
        
      if ((fabs(tmpha) <= 15.0) && (fabs(tmpdec) <= 1.0))
      {
        offsetdec = tmpdec;
        offsetha = tmpha;
        pmodel = (pmodel | OFFSET);
      }      
      
    }
    else if ((j == 1) && (strcmp(tmpcmd,"clear") == 0))
    {
      pmodel = (pmodel & ~(OFFSET));
      offsetdec = 0.; 
      offsetha = 0.;                 
    }
           
  }
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}

int send_polar_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];
  
  
  /* Send the requested data */
  
  if ( pmodel == (pmodel | POLAR) )
  {
    snprintf(tbuf, SZ_LINE, "%s %lf %lf \n", "on",  polaraz, polaralt);
  }
  else
  {
    snprintf(tbuf, SZ_LINE, "%s %lf %lf \n", "off", polaraz, polaralt);
  }
   
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_polar_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
  double tmpaz;
  double tmpalt;
  char tmpcmd[SZ_LINE]; 
  int j;

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    j=sscanf(paramlist,"%s %lf %lf", tmpcmd, &tmpaz, &tmpalt);

    if ((j == 3) && (strcmp(tmpcmd,"on") == 0))
    {
      pmodel = (pmodel | POLAR);
      polaraz = tmpaz;
      polaralt = tmpalt;
    }
    else if ((j == 3) && (strcmp(tmpcmd,"off") == 0 ))
    {
      pmodel = (pmodel & ~(POLAR));
      polaraz = tmpaz;
      polaralt = tmpalt;
    }
    else if ((j == 1) && (strcmp(tmpcmd,"on") == 0 ))
    {
      pmodel = (pmodel | POLAR);
    }
    else if ((j == 1) && (strcmp(tmpcmd,"off") == 0 ))
    {
      pmodel = (pmodel & ~(POLAR));      
    }
    else if ((j == 1) && (strcmp(tmpcmd,"clear") == 0 ))
    {
      pmodel = (pmodel & ~(POLAR));
      polaralt = 0.;
      polaraz = 0.;      
    }
           
  }
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}

int send_home_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];
  
  /* Send the requested data */
  
  if ( homeflag == TRUE )
  {
    snprintf(tbuf, SZ_LINE, "%s", "on \n");
  }
  else
  {
    snprintf(tbuf, SZ_LINE, "%s", "off \n");
  }
 
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_home_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
 

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    if( !strcmp(paramlist, "on") )
    {      
      targetra = Map24(LSTNow() - homeha);
      targetdec = homedec;
      homeflag = TRUE;
     }
    else if( !strcmp(paramlist, "off") )
    {
      homeflag = FALSE;
    }
  }
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}
 
int send_park_cb (void *client_data, void *call_data, char *paramlist,
  char **buf, size_t *len)
{
  char *s = (char *)client_data;
  XPA xpa = (XPA)call_data;
  char tbuf[SZ_LINE];
  
  /* Send the requested data */
  
  if ( parkflag == TRUE )
  {
    snprintf(tbuf, SZ_LINE, "%s", "on \n");
  }
  else
  {
    snprintf(tbuf, SZ_LINE, "%s", "off \n");
  }
 
  if( (xpa->send_mode & XPA_MODE_FILLBUF) )
  {
    send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0);
    *len = 0;
    *buf = NULL;
  }
  /* Return the buffer and let xpa transmit it */
  else
  {
    *len = strlen(tbuf);
    *buf = (char *)xmalloc(*len);
    memcpy(*buf, tbuf, *len);
  }
  
  fflush(stdout);
  fflush(stderr);
  return(0);
}


int receive_park_cb (void *client_data, void *call_data, char *paramlist,
  char *buf, size_t len)
{
  XPA xpa = (XPA)call_data;
  char *s = (char *)client_data;
 

  /* Process paramlist */
  
  if( paramlist && *paramlist )
  {
    if( !strcmp(paramlist, "on") )
    {
      targetra = Map24(LSTNow() - parkha);
      targetdec = parkdec;
      parkflag = TRUE;
     }
    else if( !strcmp(paramlist, "off") )
    {
      parkflag = FALSE;
    }
  }
  
  /* Reset save buffer */
  if( save_buf != NULL )
  {
    xfree(save_buf);
    save_buf = NULL;
  }
  save_bytes = len;
  save_buf = (char *)xmalloc(len);
  memcpy(save_buf, buf, len);

  fflush(stdout);
  fflush(stderr);
  return(0);
}
