/* -------------------------------------------------------------------------- */
/* -                   Astronomical CCD Camera Control                      - */
/* -                         Motif User Interface                           - */
/* -                            XPA for XmCCD                               - */
/* -------------------------------------------------------------------------- */
/*                                                                            */
/* Copyright (c) 2004-2021 John Kielkopf                                      */
/* kielkopf@louisville.edu                                                    */
/*                                                                            */
/* This file is part of XmCCD.                                                */
/*                                                                            */
/* Date: February 11, 2021                                                    */
/* Version: 7.0                                                               */
/*                                                                            */
/* See CCDCOMMANDS for the xpa commands used by xmccd                         */
 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <ctype.h>

#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/ToggleB.h>
#include <Xm/FileSB.h>
#include <Xm/PushB.h>
#include <Xm/Label.h>
#include <Xm/RowColumn.h> 
#include <Xm/CascadeB.h>
#include <Xm/MessageB.h>
#include <Xm/Separator.h>
#include <Xm/SelectioB.h>
#include <Xm/Text.h>
#include <Xm/List.h>

#include <xpa.h>

#include "xmccd.h"

  

/* User interface */

XtAppContext context;
XmStringCharSet char_set=XmSTRING_DEFAULT_CHARSET;

Widget menu_bar;
Widget file_menu;
Widget file_close_item;
Widget file_exit_item;

Widget set_menu;
Widget set_image_exposure_item;
Widget set_image_number_item;
Widget set_frame_count_multi_item;
Widget set_region_item;
Widget set_ccd_temperature_item;

Widget fits_menu;
Widget fits_name_item;
Widget fits_telescope_item;
Widget fits_instrument_item;
Widget fits_target_item;

Widget filter_menu;
Widget filter_item[10];

Widget mode_menu;
Widget mode_single_item;
Widget mode_focus_item;
Widget mode_multi_item;

Widget type_menu;
Widget type_light_item;
Widget type_dark_item;
Widget type_bias_item;
Widget type_flat_item;

Widget processing_menu;
Widget processing_scripting_toggle;

Widget toplevel;

Widget set_image_exposure_dialog;
Widget set_image_number_dialog;
Widget set_frame_count_multi_dialog;
Widget set_region_dialog;
Widget set_ccd_temperature_dialog;
Widget fits_name_dialog;
Widget fits_target_dialog;
Widget fits_telescope_dialog;
Widget fits_instrument_dialog;

Widget button[3][3];
Widget command[3];
Widget label_info[6];
Widget show_info[6];
Widget form;
Widget sep_btns;
Widget sep_status;

Widget make_menu();              /* creates a menu on the menu bar */
Widget make_menu_item();         /* adds an item into the menu */
Widget make_menu_item_toggle();  /* adds a toggle button item into the menu */

/* Labels for the buttons top to bottom then left to right */

static char btn_name[][6] = {
  "NoOp", 
  "East",
  "NoOp",
  "North",
  "NoOp",
  "South",
  "NoOp",
  "West",
  "NoOp"
};

static char cmd_name[][30] = {
  "Expose",
  "Interrupt",
  "Region"
};


static char infotext[][24] = {
  "Region",
  "Exposure",
  "Temperature",
  "File name",
  "Filter",
  "Status"
};

static char infodata[][24] = {
  "-",
  "-",
  "-",
  "-",
  "-",
  "Camera not ready"
};


/* Array of dynamic labels for the filters */ 

static char filter_label[10][24] = {
  "[1]                    ",
  "[2]                    ",
  "[3]                    ",
  "[4]                    ",
  "[5]                    ",
  "[6]                    ",  
  "[7]                    ",  
  "[8]                    ",
  "[9]                    ", 
  "[10]                    "
 };


void create_menus(Widget menu_bar);      /* Create all menus            */
void menuCB();                           /* All pull-down menus         */

void set_image_exposure_dialogCB();      /* Exposure time dialog        */
void set_image_number_dialogCB();        /* Image number dialog         */
void set_frame_count_multi_dialogCB();   /* Multi frame count dialog    */
void set_region_dialogCB();              /* Region dialog               */
void set_ccd_temperature_dialogCB();     /* Temperature dialog          */
void fits_name_dialogCB();               /* Set base name dialog        */
void fits_target_dialogCB();             /* Set target dialog           */
void fits_telescope_dialogCB();          /* Set telescope dialog        */
void fits_instrument_dialogCB();         /* Set instrument dialog       */

void buttonCB();                         /* The paddle buttons          */
void commandCB();                        /* Command buttons             */

void create_menus(Widget menu_bar);      /* Creates all menus for this program  */
void menuCB();                           /* Callback for all pull-down menus    */


/* Parameter io */

void input_image_exposure();             /* Image exposure time     */
void input_image_number();               /* Image number            */
void input_frame_count_multi();          /* Multi frame count       */
void input_region();                     /* Image region            */
void input_ccd_temperature();            /* CCD temperature         */
void input_filter();                     /* Filter                  */

/* GUI parameter reporting */

void set_status_buffer(void);
void update_exposure_display();     /* Display image exposure time  */
void update_region_display();       /* Display image region         */
void update_temperature_display();  /* Display temperature control  */
void update_file_name_display();    /* Display last file name       */
void update_filter_display();       /* Display filter number        */
void update_filter_menu(int i);     /* Update drop down menu entry  */
void update_status_display();       /* Display status buffer string */
void update_all_displays();         /* Display all buffers          */

/* Interface with ds9 */

void start_ds9();                    /* Initiate ds9 display              */
void update_ds9_image(char *name);   /* XPA to ds9:  read file name       */
int  get_ds9_region();               /* xpa from ds9: send me the region  */

/* Buffers */

char buf[256];                   /* General purpose character buffer */
char status_buf[24];             /* Short buffer for status string */

/* Interface flags and counters */

int  quiet = TRUE;
int  started = FALSE;
int  ccdflag = STATUS_OFF;
int  interruptflag = FALSE;
int  regionflag = FALSE;
int  acquire = SINGLE;
int  frame = LIGHT;
int  sequence = 0;
int  frame_count_multi = FRAMECOUNTMULTI;
int  image_number = 1;
int  scripting = FALSE;
char base_name[64]; 
char file_name[64];
char filter_name[24];

/* Fits header strings available through INDI */

char fits_target[64];
char fits_telescope[64];
char fits_instrument[64];
char ccd_script[64];

/* Camera variables */

unsigned short *image_data;
char   camera_device[64];
char   camera_set_prm[1024];

double image_exposure = 1.0;
double image_exposure_remaining = 1.;
int    region_x;
int    region_y; 
int    region_w;
int    region_h;

/* Temperature control */

double setpoint;
double temperature;  
double cooler_power;  
int    cool;

/* Filter variables */

int    filter_max = FILTER_MAX;
int    filter = FILTER_START;
int    filter_wheel;

/* Camera relay controls */

int relay;
double relay_ontime = RELAYONTIME;


/* User interface management */

void init(void);
unsigned long poll_interval = POLLMS;      
void poll_interval_handler(XtPointer client_data_ptr, XtIntervalId *client_id);            
XtIntervalId poll_interval_id;
XtPointer poll_interval_data_ptr;


/* Interface to xpa */

void ccd_send_status(void);
void ccd_receive_status(void);

void ccd_send_exposure(void);
void ccd_receive_exposure(void);

void ccd_send_interrupt(void);
void ccd_receive_interrupt(void);

void ccd_send_region(void);
void ccd_receive_region(void);

void ccd_send_process(void);
void ccd_receive_process(void);

void ccd_send_relay(void);
void ccd_receive_relay(void);

void ccd_send_filter(void);
void ccd_receive_filter(void);

void ccd_send_mode(void);
void ccd_receive_mode(void);

void ccd_send_type(void);
void ccd_receive_type(void);

void ccd_send_number(void);
void ccd_receive_number(void);

void ccd_send_multicount(void);
void ccd_receive_multicount(void);

void ccd_send_temperature(void);
void ccd_receive_temperature(void);

void ccd_send_file(void);
void ccd_receive_file(void);

void ccd_send_target(void);
void ccd_receive_target(void);

void ccd_send_telescope(void);
void ccd_receive_telescope(void);

void ccd_send_instrument(void);
void ccd_receive_instrument(void);


/* GUI main starts here */

int main(int argc, char *argv[])
{
  Arg al[10];
  int ac;
  unsigned long x,y,btn_number,cmd_number;
  int info_number;
  EventMask mask;

  /* No command line arguments needed */
  
  sprintf(camera_device,"ccd");
    
  /* Exit if the server is not available */

  ccdflag = STATUS_OFF;
  
  ccd_receive_status();
  if (ccdflag != STATUS_ON)
  {
    fprintf(stderr,"XPA ccd server is not available\n");
    exit(1);
  }

      
  /* Start ds9 for image display */
  
  start_ds9();
   
  /* Create the toplevel shell */

  toplevel = XtAppInitialize(&context,"",NULL,0,&argc,argv,
      NULL,NULL,0);
  
  /* Set the default size of the window */ 

  ac=0;
  XtSetArg(al[ac],XmNwidth,400); ac++;
  XtSetArg(al[ac],XmNheight,700); ac++;
  XtSetValues(toplevel,al,ac);

  /* Create a form widget */

  ac=0;
  form=XmCreateForm(toplevel,"form",al,ac);
  XtManageChild(form);


  /* Create the menu bar and attach it to the form */
  
  ac=0;
  XtSetArg(al[ac],XmNtopAttachment,XmATTACH_FORM); ac++;
  XtSetArg(al[ac],XmNrightAttachment,XmATTACH_FORM); ac++;
  XtSetArg(al[ac],XmNleftAttachment,XmATTACH_FORM); ac++;
  menu_bar=XmCreateMenuBar(form,"menu_bar",al,ac);
  XtManageChild(menu_bar);
  
  /* Locations of buttons are in percent of window dimension */

  /* Set up the handpaddle buttons, add event handlers, attach to form */
  /* There are 9 places but only 4 are used */
  
  for (x=0; x<3; x++)
  {
    for (y=0; y<3; y++)
    {
      btn_number=3*x+y;
      if ((btn_number==1) | (btn_number==3) | (btn_number==5) | (btn_number==7) ) 
      {
        ac=0;
        XtSetArg(al[ac],XmNlabelString,
            XmStringCreate(btn_name[btn_number],char_set)); ac++;
        XtSetArg(al[ac],XmNleftAttachment,
            XmATTACH_POSITION); ac++;
        XtSetArg(al[ac],XmNleftPosition,27+x*16); ac++;
        XtSetArg(al[ac],XmNrightAttachment,
            XmATTACH_POSITION); ac++;
        XtSetArg(al[ac],XmNrightPosition,41+x*16); ac++;
        XtSetArg(al[ac],XmNtopAttachment,
            XmATTACH_POSITION); ac++;
        XtSetArg(al[ac],XmNtopPosition,9+y*9); ac++;
        XtSetArg(al[ac],XmNbottomAttachment,
            XmATTACH_POSITION); ac++;
        XtSetArg(al[ac],XmNbottomPosition, 17+y*9); ac++;
        button[x][y]=XmCreatePushButton(form,"label",al,ac);
        mask = ButtonReleaseMask | ButtonPressMask;
        XtAddEventHandler(button[x][y],mask,False,
            buttonCB,(XtPointer) btn_number);              
        XtManageChild(button[x][y]);
      }
    }
  }

  /* Create a separator widget and attach it to the form */

  ac=0;
  XtSetArg(al[ac],XmNtopAttachment,XmATTACH_POSITION); ac++;
  XtSetArg(al[ac],XmNtopPosition,42); ac++;
  XtSetArg(al[ac],XmNrightAttachment,XmATTACH_FORM); ac++; 
  XtSetArg(al[ac],XmNleftAttachment,XmATTACH_FORM); ac++;  
  XtSetArg(al[ac],XmNbottomAttachment,XmATTACH_NONE); ac++;  
  sep_btns=XmCreateSeparator(form,"sep",al,ac);
  XtManageChild(sep_btns);   
 
  /* Set up the information label widgets and attach them to the form */

  for  (x=0; x<2; x++)
  {
    for (y=0; y<3; y++)
    {
      info_number=2*y+x;
      ac=0;
      XtSetArg(al[ac],XmNlabelString,
        XmStringCreate(infotext[info_number],char_set)); ac++;
      XtSetArg(al[ac],XmNleftAttachment,
        XmATTACH_POSITION); ac++;
      XtSetArg(al[ac],XmNleftPosition,5+x*50); ac++;
      XtSetArg(al[ac],XmNrightAttachment,
        XmATTACH_POSITION); ac++;
      XtSetArg(al[ac],XmNrightPosition,45+x*50); ac++;
      XtSetArg(al[ac],XmNtopAttachment,
        XmATTACH_POSITION); ac++;
      XtSetArg(al[ac],XmNtopPosition,47+y*6); ac++;
      XtSetArg(al[ac],XmNbottomAttachment,
        XmATTACH_POSITION); ac++;
      XtSetArg(al[ac],XmNbottomPosition,49+y*6); ac++;
      label_info[info_number]=XmCreateLabel(form,"label",al,ac);
      XtManageChild(label_info[info_number]); 
    }
  }

  /* Set up the information data widgets and attach them to the form */

  for  (x=0; x<2; x++)
  {
    for (y=0; y<3; y++)
    {
      info_number=2*y+x;
      ac=0;
      XtSetArg(al[ac],XmNlabelString,
        XmStringCreate(infodata[info_number],char_set)); ac++;
      XtSetArg(al[ac],XmNleftAttachment,
        XmATTACH_POSITION); ac++;
      XtSetArg(al[ac],XmNleftPosition,5+x*50); ac++;
      XtSetArg(al[ac],XmNrightAttachment,
        XmATTACH_POSITION); ac++;
      XtSetArg(al[ac],XmNrightPosition,45+x*50); ac++;
      XtSetArg(al[ac],XmNtopAttachment,
        XmATTACH_POSITION); ac++;
      XtSetArg(al[ac],XmNtopPosition,49+y*6); ac++;
      XtSetArg(al[ac],XmNbottomAttachment,
        XmATTACH_POSITION); ac++;
      XtSetArg(al[ac],XmNbottomPosition,51+y*6); ac++;
      show_info[info_number]=XmCreateLabel(form,"label",al,ac);
      XtManageChild(show_info[info_number]); 
    }
  }

  /* Create a separator widget and attach it to the form */

  ac=0;
  XtSetArg(al[ac],XmNtopAttachment,XmATTACH_POSITION); ac++;
  XtSetArg(al[ac],XmNtopPosition,70); ac++;
  XtSetArg(al[ac],XmNrightAttachment,XmATTACH_FORM); ac++; 
  XtSetArg(al[ac],XmNleftAttachment,XmATTACH_FORM); ac++;  
  XtSetArg(al[ac],XmNbottomAttachment,XmATTACH_NONE); ac++;      
  sep_status=XmCreateSeparator(form,"sep",al,ac);
  XtManageChild(sep_status);   

  /* Set up the 3 command buttons and attach them to the form */

  for (y=0; y<3; y++)
  {
    cmd_number=y;
    ac=0;
    XtSetArg(al[ac],XmNlabelString,
      XmStringCreate(cmd_name[cmd_number],char_set)); ac++;
    XtSetArg(al[ac],XmNleftAttachment,
      XmATTACH_POSITION); ac++;
    XtSetArg(al[ac],XmNleftPosition,20); ac++;
    XtSetArg(al[ac],XmNrightAttachment,
      XmATTACH_POSITION); ac++;
    XtSetArg(al[ac],XmNrightPosition,80); ac++;
    XtSetArg(al[ac],XmNtopAttachment,
      XmATTACH_POSITION); ac++;
    XtSetArg(al[ac],XmNtopPosition,74+y*8); ac++;
    XtSetArg(al[ac],XmNbottomAttachment,
      XmATTACH_POSITION); ac++;
    XtSetArg(al[ac],XmNbottomPosition, 80+y*8); ac++;
    command[y]=XmCreatePushButton(form,"label",al,ac);
    XtManageChild(command[y]);
    XtAddCallback(command[y],XmNactivateCallback,
      commandCB,(XtPointer) cmd_number);
  }

  /* Create prompt dialogs and leave them unmanaged until needed */


  /* Image exposure */

  ac=0;
  XtSetArg(al[ac], XmNselectionLabelString,
    XmStringCreateLtoR("Enter time (s): ",char_set)); ac++;
  XtSetArg(al[ac], XmNdialogTitle,
    XmStringCreateLtoR("Image Exposure",char_set)); ac++;
  set_image_exposure_dialog=XmCreatePromptDialog(toplevel,"dialog",al,ac);
  XtAddCallback(set_image_exposure_dialog, XmNokCallback, set_image_exposure_dialogCB, (int *) OK);
  XtAddCallback(set_image_exposure_dialog, XmNcancelCallback, set_image_exposure_dialogCB, (int *) CANCEL);
  XtUnmanageChild (XmSelectionBoxGetChild (set_image_exposure_dialog, XmDIALOG_HELP_BUTTON));
 
  /* Image number */

  ac=0;
  XtSetArg(al[ac], XmNselectionLabelString,
    XmStringCreateLtoR("Enter new image number: ",char_set)); ac++;
  XtSetArg(al[ac], XmNdialogTitle,
    XmStringCreateLtoR("Image Number",char_set)); ac++;
  set_image_number_dialog=XmCreatePromptDialog(toplevel,"dialog",al,ac);
  XtAddCallback(set_image_number_dialog, XmNokCallback, set_image_number_dialogCB, (int *) OK);
  XtAddCallback(set_image_number_dialog, XmNcancelCallback, set_image_number_dialogCB, (int *) CANCEL);
  XtUnmanageChild (XmSelectionBoxGetChild (set_image_number_dialog, XmDIALOG_HELP_BUTTON));

  /* Frame count multi */

  ac=0;
  XtSetArg(al[ac], XmNselectionLabelString,
    XmStringCreateLtoR("Enter maximum multiframe count: ",char_set)); ac++;
  XtSetArg(al[ac], XmNdialogTitle,
    XmStringCreateLtoR("Multiframe Maximum",char_set)); ac++;
  set_frame_count_multi_dialog=XmCreatePromptDialog(toplevel,"dialog",al,ac);
  XtAddCallback(set_frame_count_multi_dialog, XmNokCallback, set_frame_count_multi_dialogCB, (int *) OK);
  XtAddCallback(set_frame_count_multi_dialog, XmNcancelCallback, set_frame_count_multi_dialogCB, (int *) CANCEL);
  XtUnmanageChild (XmSelectionBoxGetChild (set_frame_count_multi_dialog, XmDIALOG_HELP_BUTTON));
  
  /* Image region */

  ac=0;
  XtSetArg(al[ac], XmNselectionLabelString,
    XmStringCreateLtoR("Enter image x,y,w,h : ",char_set)); ac++;
  XtSetArg(al[ac], XmNdialogTitle,
    XmStringCreateLtoR("Image Region",char_set)); ac++;
  XtSetArg(al[ac], XmNokLabelString,
    XmStringCreateLtoR("On",char_set)); ac++;
  XtSetArg(al[ac], XmNhelpLabelString,
    XmStringCreateLtoR("Off",char_set)); ac++;
  set_region_dialog=XmCreatePromptDialog(toplevel,"dialog",al,ac);
  XtAddCallback(set_region_dialog, XmNokCallback, set_region_dialogCB, (int *) REGION_ON);
  XtAddCallback(set_region_dialog, XmNcancelCallback, set_region_dialogCB, (int *) CANCEL);
  XtAddCallback(set_region_dialog, XmNhelpCallback, set_region_dialogCB, (int *) REGION_OFF);

  /* Temperature */

  ac=0;
  XtSetArg(al[ac], XmNselectionLabelString,
    XmStringCreateLtoR("Enter temperature (C): ",char_set)); ac++;
  XtSetArg(al[ac], XmNdialogTitle,
    XmStringCreateLtoR("CCD Temperature Setpoint",char_set)); ac++;
  XtSetArg(al[ac], XmNokLabelString,
    XmStringCreateLtoR("On",char_set)); ac++;
  XtSetArg(al[ac], XmNhelpLabelString,
    XmStringCreateLtoR("Off",char_set)); ac++;
  set_ccd_temperature_dialog=XmCreatePromptDialog(toplevel,"dialog",al,ac);
  XtAddCallback(set_ccd_temperature_dialog, XmNokCallback, set_ccd_temperature_dialogCB, (int *) COOL_ON);
  XtAddCallback(set_ccd_temperature_dialog, XmNcancelCallback, set_ccd_temperature_dialogCB, (int *) CANCEL);
  XtAddCallback(set_ccd_temperature_dialog, XmNhelpCallback, set_ccd_temperature_dialogCB, (int *) COOL_OFF);

  /* Set base image file name */

  ac=0;
  XtSetArg(al[ac], XmNselectionLabelString,
    XmStringCreateLtoR("Base for image file names: ",char_set)); ac++;
  XtSetArg(al[ac], XmNdialogTitle,
    XmStringCreateLtoR("Image file name entry",char_set)); ac++;
  fits_name_dialog=XmCreatePromptDialog(toplevel,"dialog",al,ac);
  XtAddCallback(fits_name_dialog, XmNokCallback, fits_name_dialogCB, 
    (int *) OK);
  XtAddCallback(fits_name_dialog, XmNcancelCallback, fits_name_dialogCB, 
    (int *) CANCEL);
  XtUnmanageChild (XmSelectionBoxGetChild (fits_name_dialog, 
    XmDIALOG_HELP_BUTTON));

  /* Set target */

  ac=0;
  XtSetArg(al[ac], XmNselectionLabelString,
    XmStringCreateLtoR("FITS header TARGET: ",char_set)); ac++;
  XtSetArg(al[ac], XmNdialogTitle,
    XmStringCreateLtoR("FITS header target entry",char_set)); ac++;
  fits_target_dialog=XmCreatePromptDialog(toplevel,"dialog",al,ac);
  XtAddCallback(fits_target_dialog, XmNokCallback, fits_target_dialogCB, 
    (int *) OK);
  XtAddCallback(fits_target_dialog, XmNcancelCallback, 
    fits_target_dialogCB, (int *) CANCEL);
  XtUnmanageChild (XmSelectionBoxGetChild (fits_target_dialog, 
    XmDIALOG_HELP_BUTTON));

  /* Set telescope */

  ac=0;
  XtSetArg(al[ac], XmNselectionLabelString,
    XmStringCreateLtoR("FITS header TELESCOPE: ",char_set)); ac++;
  XtSetArg(al[ac], XmNdialogTitle,
    XmStringCreateLtoR("FITS header telescope entry",char_set)); ac++;
  fits_telescope_dialog=XmCreatePromptDialog(toplevel,"dialog",al,ac);
  XtAddCallback(fits_telescope_dialog, XmNokCallback, 
    fits_telescope_dialogCB, (int *) OK);
  XtAddCallback(fits_telescope_dialog, XmNcancelCallback, 
    fits_telescope_dialogCB, (int *) CANCEL);
  XtUnmanageChild (XmSelectionBoxGetChild (fits_telescope_dialog, 
    XmDIALOG_HELP_BUTTON));

  /* Set instrument */

  ac=0;
  XtSetArg(al[ac], XmNselectionLabelString,
    XmStringCreateLtoR("FITS header INSTRUMENT: ",char_set)); ac++;
  XtSetArg(al[ac], XmNdialogTitle,
    XmStringCreateLtoR("FITS header instrument entry",char_set)); ac++;
  fits_instrument_dialog=XmCreatePromptDialog(toplevel,"dialog",al,ac);
  XtAddCallback(fits_instrument_dialog, XmNokCallback, 
    fits_instrument_dialogCB, (int *) OK);
  XtAddCallback(fits_instrument_dialog, XmNcancelCallback, 
    fits_instrument_dialogCB, (int *) CANCEL);
  XtUnmanageChild (XmSelectionBoxGetChild (fits_instrument_dialog, 
    XmDIALOG_HELP_BUTTON));

  /* Create the menubar */

  create_menus(menu_bar); 
    
  /* Disable menu items not used because of hardware limitations */

  if ( filter_max <= 1 )
  {
    XtSetSensitive(filter_menu,False);
  }   

  /* Set the polling interval */

  poll_interval_id = XtAppAddTimeOut(context,
    poll_interval,poll_interval_handler,poll_interval_data_ptr);  

    
  /* Start the user interface */
  
  XtRealizeWidget(toplevel);
  XtAppMainLoop(context);

  exit(0);
}


/* Add an item into a menu in the menubar */   

Widget make_menu_item(char *item_name, unsigned long client_data, Widget menu)
{
  int ac;
  Arg al[10];
  Widget item;

  ac = 0;
  XtSetArg(al[ac], XmNlabelString,
    XmStringCreateLtoR(item_name,char_set)); ac++;      
  item=XmCreatePushButton(menu,item_name,al,ac);
  XtManageChild(item);
  XtAddCallback (item,XmNactivateCallback,menuCB,(int *) client_data);      
  XtSetSensitive(item,True);
  return(item);
}


/* Add a toggle item into a menu in the menubar */ 

Widget make_menu_item_toggle(char *item_name, unsigned long client_data, Widget menu)
{
  int ac;
  Arg al[10];
  Widget item;

  ac = 0;
  XtSetArg(al[ac], XmNlabelString,
      XmStringCreateLtoR(item_name,char_set)); ac++; 
  item=XmCreateToggleButton(menu,item_name,al,ac);
  XtManageChild(item);
  XtAddCallback (item,XmNvalueChangedCallback,menuCB,(XtPointer) client_data);      
  XtSetSensitive(item,True);
  return(item);
}

/* Create a menu on the menu bar */

Widget make_menu(char *menu_name, Widget menu_bar)
{
  int ac;
  Arg al[10];
  Widget menu, cascade;

  menu=XmCreatePulldownMenu(menu_bar,menu_name,NULL,0);
  ac=0;
  XtSetArg(al[ac],XmNsubMenuId,menu);  ac++;
  XtSetArg(al[ac],XmNlabelString,
    XmStringCreateLtoR(menu_name,char_set)); ac++;
  cascade=XmCreateCascadeButton(menu_bar,menu_name,al,ac);      
  XtManageChild (cascade); 
  return(menu);
}


/* Create all the menubar entries organized into submenus*/

void create_menus(Widget menu_bar)
{
  int ac;
  Arg al[10];
  int i;
     
  /* Create the file menu */
  file_menu = make_menu("File",menu_bar);
  file_exit_item = make_menu_item("Exit XmCCD",FILEEXIT,file_menu);
  
  /* Create the set menu */
  set_menu = make_menu("Set",menu_bar);
  set_image_exposure_item = make_menu_item("Image exposure",SETIMAGEEXPOSURE,set_menu);
  set_image_number_item = make_menu_item("Image number",SETIMAGENUMBER,set_menu);
  set_frame_count_multi_item = make_menu_item("Multiframe count",SETFRAMECOUNTMULTI,set_menu);
  set_region_item = make_menu_item("Image region",SETREGION,set_menu);
  set_ccd_temperature_item = make_menu_item("CCD temperature",SETCCDTEMPERATURE,set_menu);

  fits_menu = make_menu("FITS",menu_bar);
  fits_name_item = make_menu_item("Base name",FITSNAME,fits_menu);
  fits_target_item = make_menu_item("Target",FITSTARGET,fits_menu);
  fits_telescope_item = make_menu_item("Telescope",FITSTELESCOPE,fits_menu);
  fits_instrument_item = make_menu_item("Instrument",FITSINSTRUMENT,fits_menu);
  
  /* Create the filter menu */
  filter_menu = make_menu("Filter",menu_bar);
  for ( i=0; i<filter_max; i++ )
  {
    filter_item[i] = make_menu_item_toggle(filter_label[i],FILTER1+i,filter_menu);
  }
   
  /* Add radio behavior to the filter menu */
  ac=0;
  XtSetArg(al[ac],XmNradioBehavior,True); ac++;
  XtSetValues(filter_menu,al,ac);

  /* Create a toggle button mode menu */
  mode_menu = make_menu("Mode",menu_bar);
  mode_single_item = make_menu_item_toggle("Single",MODESINGLE,mode_menu);
  mode_focus_item = make_menu_item_toggle("Focus",MODEFOCUS,mode_menu);
  mode_multi_item  = make_menu_item_toggle("Multi",MODEMULTI,mode_menu);
     
  /* Add radio behavior to the mode menu */
  ac=0;
  XtSetArg(al[ac],XmNradioBehavior,True); ac++;
  XtSetValues(mode_menu,al,ac);
  
  /* Set an initial mode_menu button state */
  XmToggleButtonSetState(mode_single_item, True, False);
           
  /* Create a toggle button image type menu */
  type_menu = make_menu("Type",menu_bar);
  type_light_item = make_menu_item_toggle("Light",TYPELIGHT,type_menu);
  type_dark_item = make_menu_item_toggle("Dark",TYPEDARK,type_menu);
  type_bias_item = make_menu_item_toggle("Bias",TYPEBIAS,type_menu);
  type_flat_item = make_menu_item_toggle("Flat",TYPEFLAT,type_menu);
  
       
  /* Add radio behavior to the type menu */
  ac=0;
  XtSetArg(al[ac],XmNradioBehavior,True); ac++;
  XtSetValues(type_menu,al,ac);
  
  /* Set the initial type_menu button */
  XmToggleButtonSetState(type_light_item, True, False);
  
  /* Create the processing menu */
  processing_menu = make_menu("Processing", menu_bar);
  processing_scripting_toggle = make_menu_item_toggle("Scripting", PROCSCRIPTING, processing_menu);
  
}
/* Callback on menubar action sorts requests based on client_data */

void menuCB(Widget w, int client_data, XmAnyCallbackStruct *call_data)
{
  int i;

  /* Close this program and leave xpaccd running */
  
  if (client_data==FILEEXIT)   
  {
    ccdflag = STATUS_OFF;
    free(image_data);
    exit(0);
  } 
     
  if (client_data==SETIMAGEEXPOSURE)
  {
    XtManageChild(set_image_exposure_dialog);
  }
    
  if (client_data==SETIMAGENUMBER) 
  {
    XtManageChild(set_image_number_dialog);
  }   
  
  if (client_data==SETFRAMECOUNTMULTI) 
  {
    XtManageChild(set_frame_count_multi_dialog);
  }  
  
  
  if (client_data==SETREGION)
  {
    XtManageChild(set_region_dialog);
  }
  
  if (client_data==SETCCDTEMPERATURE) 
  {
    XtManageChild(set_ccd_temperature_dialog);
  }

  if (client_data==FITSNAME)
  {
    XtManageChild(fits_name_dialog);
  } 

  if (client_data==FITSTARGET)
  {
    XtManageChild(fits_target_dialog);
  } 

  if (client_data==FITSTELESCOPE)
  {
    XtManageChild(fits_telescope_dialog);
  }
  
  if (client_data==FITSINSTRUMENT)
  {
    XtManageChild(fits_instrument_dialog);
  }

  for (i=0; i<filter_max; i++)
  {
    if ( ( client_data == (FILTER1 + i)) && (filter_max > i) )
    {
      if( XmToggleButtonGetState(filter_item[i]) )
      {
        filter = i + 1;
        ccd_send_filter();
        ccd_receive_filter();          
      }
    }
  }

  if (client_data==MODESINGLE)
  {
    if( XmToggleButtonGetState(mode_single_item) )
    {
      acquire = SINGLE;
      ccd_send_mode();
      ccd_receive_mode();
    }
  }
  
  if (client_data==MODEFOCUS)
  {
    if( XmToggleButtonGetState(mode_focus_item) )
    {
      acquire = FOCUS;
      ccd_send_mode();
      ccd_receive_mode();     
    }
  }
      
  if (client_data==MODEMULTI)
  {
    if( XmToggleButtonGetState(mode_multi_item) )
    {
      acquire = MULTI;
      ccd_send_mode();
      ccd_receive_mode();     
    }
  }
  
  if (client_data==TYPELIGHT)
  {
    if( XmToggleButtonGetState(type_light_item) )
    {
      frame = LIGHT;
      ccd_send_type();
      ccd_receive_type();
    }
  }
  if (client_data==TYPEDARK)
  {
    if( XmToggleButtonGetState(type_dark_item) )
    {
      frame = DARK;
      ccd_send_type();
      ccd_receive_type();
    }
  }
  if (client_data==TYPEBIAS)
  {
    if( XmToggleButtonGetState(type_bias_item) )
    {
      frame = BIAS;
      ccd_send_type();
      ccd_receive_type();
    }
  }  
  if (client_data==TYPEFLAT)
  {
    if( XmToggleButtonGetState(type_flat_item) )
    {
      frame = FLAT;
      ccd_send_type();
      ccd_receive_type();
    }
  }  
  if (client_data==PROCSCRIPTING)
  { 
    if( XmToggleButtonGetState(processing_scripting_toggle) )
    {
      scripting = TRUE;
    }
    else
    {
      scripting = FALSE;
    }      
    ccd_send_process();
    ccd_receive_process();
    if (scripting == TRUE)
    {
      XmToggleButtonSetState(processing_scripting_toggle, True, False);
    }
    else
    {
      XmToggleButtonSetState(processing_scripting_toggle, False, False);
    }  
  } 
    
  
  
  /* Take no action on cancel */
  
  if (client_data != CANCEL)
  {
     update_all_displays();
  }

}


  

/* Dialog for user input of file base name */

void fits_name_dialogCB(w,client_data,call_data)
  Widget w;
  int client_data;
  XmSelectionBoxCallbackStruct  *call_data;
{  
  char *s;
  
  switch (client_data)
  {
    case OK:
      XmStringGetLtoR(call_data->value,char_set,&s);
      strncpy(base_name,s,64);
      base_name[63]='\0';
      XtFree(s);
      ccd_send_file();
      ccd_receive_file();
      break;
    case CANCEL:
      break;
  }
  XtUnmanageChild(w);
}


/* Dialog for fits target entry */

void fits_target_dialogCB(w,client_data,call_data)
  Widget w;
  int client_data;
  XmSelectionBoxCallbackStruct  *call_data;
{  
  char *s;
  
  switch (client_data)
  {
    case OK:
      XmStringGetLtoR(call_data->value,char_set,&s);
      strncpy(fits_target,s,64);
      fits_target[63]='\0';
      XtFree(s);
      if (!quiet )
      {
        fprintf(stderr, "Target string: %s\n", fits_target);
      }
      ccd_send_target();
      ccd_receive_target();
      break;
    case CANCEL:
      break;
  }
  XtUnmanageChild(w);
}

/* Dialog for fits telescope entry */

void fits_telescope_dialogCB(w,client_data,call_data)
  Widget w;
  int client_data;
  XmSelectionBoxCallbackStruct  *call_data;
{  
  char *s;
  
  switch (client_data)
  {
    case OK:
      XmStringGetLtoR(call_data->value,char_set,&s);
      strncpy(fits_telescope,s,64);
      fits_telescope[63]='\0';
      XtFree(s);
      ccd_send_telescope();
      ccd_receive_telescope();
      break;
    case CANCEL:
      break;
  }
  XtUnmanageChild(w);
}

/* Dialog for user input of fits file header instrument entry */

void fits_instrument_dialogCB(w,client_data,call_data)
  Widget w;
  int client_data;
  XmSelectionBoxCallbackStruct  *call_data;
{  
  char *s;
  
  switch (client_data)
  {
    case OK:
      XmStringGetLtoR(call_data->value,char_set,&s);
      strncpy(fits_instrument,s,64);
      fits_instrument[63] = '\0';
      XtFree(s);
      ccd_send_instrument();
      ccd_receive_instrument();
      break;
    case CANCEL:
      break;
  }
  XtUnmanageChild(w);
}


/* Dialog for user input of image exposure time */

void set_image_exposure_dialogCB(w,client_data,call_data)
  Widget w;
  int client_data;
  XmSelectionBoxCallbackStruct  *call_data;
{    
  char *s;

  switch (client_data)
  {
    case OK:
      XmStringGetLtoR(call_data->value,char_set,&s);
      image_exposure = atof(s);
      if ( image_exposure < MINEXP )
      {
        image_exposure = MINEXP;
      }
      if ( image_exposure > MAXEXP )
      {
        image_exposure = MAXEXP;
      }
      image_exposure_remaining = image_exposure;     
      ccd_send_exposure();
      ccd_receive_exposure();
      update_exposure_display();
      XtFree(s);
      break;
    case CANCEL:
      break;
  }
  XtUnmanageChild(w);

}


/* Dialog for user input of image number */
/* Should add warnings here about possibly overwriting existing files */
/* This allows for changing number sequence during a run */

void set_image_number_dialogCB(w,client_data,call_data)
  Widget w;
  int client_data;
  XmSelectionBoxCallbackStruct  *call_data;
{    
  char *s;
  int new_number;

  switch (client_data)
  {
    case OK:
      XmStringGetLtoR(call_data->value,char_set,&s);
      new_number = (int) atof(s);
      if ( new_number < 2 )
      {
        new_number = 1;
      }
      image_number = new_number;
      ccd_send_number();
      ccd_receive_number();
      update_all_displays();
      XtFree(s);
      break;
    case CANCEL:
      break;
  }
  XtUnmanageChild(w);
}


/* Dialog for user input of frame count multi */

void set_frame_count_multi_dialogCB(w,client_data,call_data)
  Widget w;
  int client_data;
  XmSelectionBoxCallbackStruct *call_data;
{    
  char *s;

  switch (client_data)
  {
    case OK:
      XmStringGetLtoR(call_data->value,char_set,&s);
      frame_count_multi = (int) atof(s);
      if ( frame_count_multi < 2 )
      {
        frame_count_multi = 2;
      }
      ccd_send_multicount();
      ccd_receive_multicount();
      XtFree(s);
      break;
    case CANCEL:
      break;
  }
  XtUnmanageChild(w);
}


/* Dialog for user input of image region */

void set_region_dialogCB(w,client_data,call_data)
    Widget w;
    int client_data;
    XmSelectionBoxCallbackStruct  *call_data;
{  
  char *s;
  int in_x, in_y, in_w, in_h;

  switch (client_data)
  {
    case REGION_ON:

      /* Set the switch on */
      
      regionflag = TRUE;
      XmStringGetLtoR(call_data->value,char_set,&s);
      if (sscanf(s, "%d,%d,%d,%d", &in_x, &in_y, &in_w, &in_h) == 4)
      {
        
        /* Take anything */
        /* Accepted values will be checked and returned by xpaccd */

        region_x = in_x;
        region_y = in_y;
        region_w = in_w;
        region_h = in_h;
        ccd_send_region();
        ccd_receive_region();

      }
      XtFree(s); 
      break;

    case REGION_OFF:
      
      /* Set the switch off */
      
      regionflag = FALSE;
      ccd_send_region();
      ccd_receive_region();
      break;  

    case CANCEL:
      break;
  }
  XtUnmanageChild(w);
}

/* Dialog for user input of ccd temperature setpoint */

void set_ccd_temperature_dialogCB(w,client_data,call_data)
  Widget w;
  int client_data;
  XmSelectionBoxCallbackStruct  *call_data;
{    
  char *s;

  switch (client_data)
  {
    case COOL_ON:
      XmStringGetLtoR(call_data->value,char_set,&s);
      setpoint=atof(s);
      XtFree(s); 
      cool = TRUE;        
      ccd_send_temperature();
      ccd_receive_temperature(); 
      break;
    case COOL_OFF:
      cool = FALSE;
      setpoint = 20.;
      ccd_send_temperature();
      ccd_receive_temperature();
      break;    
    case CANCEL:
      break;
  }
  XtUnmanageChild(w);
}


/* Callback function for the radio buttons that select guide grid function */

/* Callback function for the 9 grid buttons */

void buttonCB(w,client_data,call_event)
  Widget w;
  int client_data;
  XEvent *call_event;
{
  int n;
  int et = call_event->type;
  int dn,up;
   
  /* identify the button number n = 3*x+y */
  n=client_data;

  /* identify the action */
  
  dn = et == ButtonPress;
  up = et == ButtonRelease;
      
  /* respond to the request */
  

  if(dn)
  {
    switch (n) 
    {
   
      /* NoOp */
      case 0:
      break;

      /* E */
      case 1: 
        relay = EAST;
        ccd_send_relay(); 
      break;

      /* NoOp */
      case 2: 
      break;

      /* N */
      case 3: 
        relay = NORTH;
        ccd_send_relay();
      break;

      /* NoOp */
      case 4:
      break;

      /* S */
      case 5: 
        relay = SOUTH;
        ccd_send_relay();
      break;

      /* NoOp */
      case 6:
      break;

      /* W */
      case 7:
        relay = WEST;
        ccd_send_relay();  
      break;

      /* NoOp */
      case 8: 
      break;    

    }
  }      
        
  if(up)
  {     
    /* Wait for the telescope to respond before accepting another cycle */
    
    usleep(relay_ontime*1000000.);
  }


}

/* Callback for the camera command buttons */

void commandCB(Widget w, int client_data, XmAnyCallbackStruct *call_data)
{
  
  int n, cmd_number;

  /* Identify the button */
  cmd_number = client_data;

  /* Respond to the request */
  /* Test ccd state, set flags, execute request */
  n = cmd_number;

  switch (n) 
  {

    /* Expose */
    case 0:
      
      /* Ask the server to start the sequence */
      sequence = 1;
      ccd_send_exposure();
      ccd_receive_exposure();
      break;
      
    /* Interrupt */
    case 1:

      /* Stop the sequence */
      sequence = 0;
      ccd_send_interrupt();
      ccd_receive_interrupt();
      ccd_send_exposure();
      ccd_receive_exposure();       
      break;

    /* Capture region parameters from ds9 */
    case 2:
      get_ds9_region();
      ccd_send_region();
      ccd_receive_region();
      break;
  }
  
}


 
/* Update imaging ccd exposure time in the window */

void update_exposure_display()
{
  XmString xmstr;
  Arg al[10];
  int ac;

  sprintf(buf,"%4.3lf",image_exposure_remaining);
  xmstr = XmStringCreateLtoR(buf,char_set);
  ac=0;
  XtSetArg(al[ac],XmNlabelString,xmstr); ac++;
  XtSetValues(show_info[1],al,ac);   
  XmStringFree(xmstr);
}  
   

/* Update image region selection in the window */

void update_region_display()
{
  XmString xmstr;
  Arg al[10];
  int ac;

  if ( regionflag == TRUE )
  {
  sprintf(buf,"%d %d %d %d [On]",
    region_x, region_y, region_w, region_h);
  }
  else
  {
  sprintf(buf,"%d %d %d %d [Off]",
    region_x, region_y, region_w, region_h);
  }
  
  xmstr = XmStringCreateLtoR(buf,char_set);
  ac=0;
  XtSetArg(al[ac],XmNlabelString,xmstr); ac++;
  XtSetValues(show_info[0],al,ac);   
  XmStringFree(xmstr);
} 



/* Update ccd temperature in the window                  */
/* Values must have been previously read from the camera */

void update_temperature_display()
{
  XmString xmstr;
  Arg al[10];
  int ac;
  if (cool == 1)
  {
    sprintf(buf,"%3.1lf [%3.1lf (On)]", temperature,setpoint);
  }
  else
  {
    sprintf(buf,"%3.1lf [%3.1lf (Off)]", temperature,setpoint); 
  }
  xmstr = XmStringCreateLtoR(buf,char_set);
  ac=0;
  XtSetArg(al[ac],XmNlabelString,xmstr); ac++;
  XtSetValues(show_info[2],al,ac);   
  XmStringFree(xmstr);
} 

/* Update the file name from XPA in the main window */

void update_file_name_display()
{
  XmString xmstr;
  Arg al[10];
  int ac; 
    
  xmstr = XmStringCreateLtoR(file_name,char_set);
    
  ac=0;
  XtSetArg(al[ac],XmNlabelString,xmstr); ac++;
  XtSetValues(show_info[3],al,ac);   
  XmStringFree(xmstr);
}       

/* Update filter data in the main window */

void update_filter_display()
{
  XmString xmstr;
  Arg al[10];
  int ac; 
  sprintf(buf,"[%d] %s", filter, filter_name);
  xmstr = XmStringCreateLtoR(buf,char_set);
  
  ac=0;
  XtSetArg(al[ac],XmNlabelString,xmstr); ac++;
  XtSetValues(show_info[4],al,ac);   
  XmStringFree(xmstr);
} 

/* Update filter name in the drop down menu */
/* Index starts at 0 while filters are numbered from 1 */

void update_filter_menu(int i)
{
  XmString xmstr;
  Arg al[10];
  int ac; 

  sprintf(filter_label[i],"[%d] %s", i+1, filter_name);
  xmstr = XmStringCreateLtoR(filter_label[i],char_set);
  
  ac=0;
  XtSetArg(al[ac],XmNlabelString,xmstr); ac++;
  XtSetValues(filter_item[i],al,ac);   
  XmStringFree(xmstr);
} 

/* Update status in the window */

void update_status_display()
{
  XmString xmstr;
  Arg al[10];
  int ac;
  set_status_buffer();
  xmstr = XmStringCreateLtoR(status_buf,char_set);
  ac=0;
  XtSetArg(al[ac],XmNlabelString,xmstr); ac++;
  XtSetValues(show_info[5],al,ac);   
  XmStringFree(xmstr);
}   
 
/* Update all display buffers */

void update_all_displays()
{
  update_status_display();
  update_file_name_display();
  update_temperature_display();
  update_filter_display();
  update_exposure_display();
  update_region_display();
}   



/* User input of image ccd exposure time */

void input_image_exposure() 
{
  XtManageChild(set_image_exposure_dialog);
}

/* User input of multiframe count max */

void input_frame_count_multi() 
{
  XtManageChild(set_frame_count_multi_dialog);
}

/* User input of ccd temperature setpoint */

void input_setpoint() 
{
  XtManageChild(set_ccd_temperature_dialog);
}




/* Set panel status buffer based on information from the user interface */

void set_status_buffer(void)
{
  
  /* Set the display message */
     
  if (sequence == 1)
  {
    if(acquire == SINGLE)
    {
      if(frame == DARK)
      {
        sprintf(status_buf,"Single dark");
      }
      else
      {
        sprintf(status_buf,"Single");
      }  
    }
    else if(acquire == FOCUS)
    {
      if(frame == DARK)
      {
        sprintf(status_buf,"Focus dark");
      }
      else
      {
        sprintf(status_buf,"Focus");
      }               
    }
    else if(acquire == MULTI)
    {
      if(frame == DARK)
      {
        sprintf(status_buf,"Multiple dark");
      }
      else
      {
        sprintf(status_buf,"Multiple");
      } 
    }
    else 
    {
      sprintf(status_buf,"Image");
    }             
  }  
  else
  {
    sprintf(status_buf,"Camera ready");
  }
}


void poll_interval_handler(XtPointer client_data_ptr, XtIntervalId *client_id) 
{
  
  /* Communicate initial settings to the XPA server */
  
  if (started == FALSE)
  {
    init();
  }      

  /* Check the server when we know updates are expected */
  
  if (sequence == 1)
  {
    ccd_receive_exposure();
  }
   
  /* Refresh the user interface */

  update_all_displays();
              
  /* Start the timer again */ 

  poll_interval_id = XtAppAddTimeOut(context, poll_interval,
    poll_interval_handler, poll_interval_data_ptr);

}  



/* Start ds9 as a new process */

void start_ds9(void)
{
  strcpy(buf, "ds9 &");
  system(buf);
}

       
/* Use xpa to read last region from ds9 and set region parameters */
/* Returns number of coordinates that have been read              */
/* A box will return 4 and a circle will return 3                 */
/* Coordinates are with respect to the lower left corner          */
/* Sets regionflag                                                */

int get_ds9_region(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char *regionptr;
  double xc,yc,dx,dy;
  
  j=0;
  nresponses = XPAGet(NULL, "ds9", "regions", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {
          
      /* Process data_buffer[i] contents */
    
      /* Format:                             */
      /*   circle(x_center,y_center,radius)  */
      /*   box(x_center,y_center,dx,dy)      */
      /*   relative to lower left            */ 
      
      regionflag = FALSE;
      regionptr=strrchr(data_buffer[i], '(' );
      if(regionptr!=NULL)
      {
        regionptr++;
        j=sscanf(regionptr,"%lf,%lf,%lf,%lf",
          &xc,&yc,&dx,&dy);
        if (j == 4)  
        {
          region_x = (int) (xc - dx/2);
          region_y = (int) (yc - dy/2);
          region_w = (int) (dx);
          region_h = (int) (dy);
          regionflag = TRUE;
        }
        else if (j == 3)  
        {
          region_x = (int) (xc - dx);
          region_y = (int) (yc - dx);
          region_w = (int) (dx + dx);
          region_h = region_w;
          regionflag = TRUE;
        }
        else
        {
          regionflag = FALSE;        
        }
      }           
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }

  return j;
}


/* User interface startup */

void init(void)
{
  if (started == TRUE)
  {
    return;
  }

  /* Update the GUI with the latest from the server */

  ccd_receive_exposure();
  ccd_receive_interrupt();
  ccd_receive_region();
  ccd_receive_filter();
  ccd_receive_mode();
  ccd_receive_type();
  ccd_receive_number();
  ccd_receive_multicount();
  ccd_receive_temperature();
  ccd_receive_file();
  ccd_receive_target();
  ccd_receive_telescope();
  ccd_receive_instrument();
}    


/* XPA client utilities */

void ccd_send_status(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];

  if ( ccdflag == STATUS_ON )
  {
    sprintf(ccdmsg, "status on");
  }
  else if ( ccdflag == STATUS_OFF )
  {
    sprintf(ccdmsg, "status off");    
  }
  else
  {
    return;
  }    
    
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}

void ccd_receive_status(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
   
  j=0;
  nresponses = XPAGet(NULL, "ccd", "status", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j = sscanf(data_buffer[i],"%s", ccdmsg);
      if (j == 1)  
      {
        if ( !strcmp(ccdmsg, "off") )
        {
          ccdflag = STATUS_OFF;
        }    
        else if ( !strcmp(ccdmsg, "on") )
        {
          ccdflag = STATUS_ON;    
        }    
      
      }        
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}


void ccd_send_exposure(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
  
  /* Send the requested data */
  
  if ( sequence == 0 )
  {
    sprintf(ccdmsg, "exposure off %lf", image_exposure);
  }
  else
  {
    sprintf(ccdmsg, "exposure on %lf", image_exposure);
  }
  
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}


void ccd_receive_exposure(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char cmd[64];
  double tmp_image_exposure;
  double tmp_image_exposure_remaining;
  
  j=0;
  nresponses = XPAGet(NULL, "ccd", "exposure", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j = sscanf(data_buffer[i],"%s %lf %lf", cmd, 
        &tmp_image_exposure_remaining, &tmp_image_exposure);
      if (j == 3)  
      {
        if( !strcmp(cmd, "on") )
        {
          sequence = 1;
        }
        else if( !strcmp(cmd, "off") )
        {
          sequence = 0;
        }
           
        image_exposure = tmp_image_exposure;
        image_exposure_remaining = tmp_image_exposure_remaining;
      }        
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}


void ccd_send_interrupt(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];

  if ( interruptflag == TRUE )
  {
    sprintf(ccdmsg, "interrupt on");
  }
  else
  {
    sprintf(ccdmsg, "interrupt off");    
  }
    
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}

void ccd_receive_interrupt(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
   
  j=0;
  nresponses = XPAGet(NULL, "ccd", "interrupt", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j = sscanf(data_buffer[i],"%s", ccdmsg);
      if (j == 1)  
      {
        if ( !strcmp(ccdmsg, "off") )
        {
          /* Make sure flag is off */
          /* Leave sequencing unaltered */
          
          interruptflag = FALSE;
        }    
        else if ( !strcmp(ccdmsg, "on") )
        {
          /* Should be in interrupted state */
          /* Make sure flag is on */
          /* Reset sequence to 0 */
          
          interruptflag = TRUE;
          sequence = 0;    
        }    
      
      }        
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}


void ccd_send_region(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
  
  /* Send the requested data */
  
  if ( regionflag == FALSE )
  {
    /* Clear resets to default CCD size and turns function off */
    
    sprintf(ccdmsg, "region off clear");
  }
  else
  {
    sprintf(ccdmsg, "region on select %d %d %d %d", 
      region_x, region_y, region_w, region_h);
  }
  
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}


void ccd_receive_region(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char cmd1[64];
  int x, y, w, h;
  
  j=0;
  nresponses = XPAGet(NULL, "ccd", "region", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j=sscanf(data_buffer[i],"%s %d %d %d %d", cmd1, &x, &y, &w, &h);
      
      if (j == 5)
      {
        if( !strcmp(cmd1, "on") )
        {
          regionflag = TRUE;
        }
        else if( !strcmp(cmd1, "off") )
        {
          regionflag = FALSE;
        }    
        region_x = x;
        region_y = y;
        region_w = w;
        region_h = h;
      }  
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}


void ccd_send_process(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];

  if ( scripting == TRUE )
  {
    sprintf(ccdmsg, "process on");
  }
  else
  {
    sprintf(ccdmsg, "process off");    
  }  
    
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}

void ccd_receive_process(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
   
  j=0;
  nresponses = XPAGet(NULL, "ccd", "process", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j = sscanf(data_buffer[i],"%s", ccdmsg);
      if (j == 1)  
      {
        if ( !strcmp(ccdmsg, "off") )
        {
          scripting = FALSE;
        }    
        else if ( !strcmp(ccdmsg, "on") )
        {
          scripting = TRUE;    
        }    
      
      }        
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}

void ccd_send_relay(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
  
  /* Send the requested data */
  
  sprintf(ccdmsg, "relay %d %lf", relay, relay_ontime );
  
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}


void ccd_receive_relay(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  int tmp_relay;
  double tmp_relay_ontime;
  
  j=0;
  nresponses = XPAGet(NULL, "ccd", "relay", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j = sscanf(data_buffer[i],"%d %lf", 
        &tmp_relay, &tmp_relay_ontime);
      if (j == 2)  
      {
         
        relay = tmp_relay;
        relay_ontime = tmp_relay_ontime;
      }        
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}


void ccd_send_filter(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
  
  /* Send the requested data */
  
  sprintf(ccdmsg, "filter %d", filter);
  
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}


void ccd_receive_filter(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char new_name[24];
  int new_filter;
  
  j=0;
  nresponses = XPAGet(NULL, "ccd", "filter", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j=sscanf(data_buffer[i],"%d %s", &new_filter, new_name);
      
      if (j == 1)
      {
        filter = new_filter;
        strncpy(filter_name, "                       ", 24);
        update_filter_menu(filter - 1);
      }        
      else if (j == 2)
      {
        filter = new_filter;
        strncpy(filter_name, new_name, 24);
        update_filter_menu(filter - 1);
      }  
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}


void ccd_send_mode(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
  
  /* Send the requested data */
    
  if (acquire == SINGLE)
  {
    sprintf(ccdmsg, "mode single");
  }
  else if (acquire == MULTI)
  {
    sprintf(ccdmsg, "mode multi");
  }
  else if (acquire == FOCUS)
  {
    sprintf(ccdmsg, "mode focus");
  }
  else
  {
    return;
  }
    
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}


void ccd_receive_mode(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char new_mode[64];
  
  j=0;
  nresponses = XPAGet(NULL, "ccd", "mode", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j=sscanf(data_buffer[i],"%s", new_mode);
      
      if (j == 1)
      {
        if( !strcmp(new_mode, "single") )
        {
          acquire = SINGLE;
        }
        else if( !strcmp(new_mode, "focus") )
        {
          acquire = FOCUS;
        }
        else if( !strcmp(new_mode, "multi") )
        {
          acquire = MULTI;
        }
      }  
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}

void ccd_send_type(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
  
  /* Send the requested data */
  
  if (frame == LIGHT)
  {
    sprintf(ccdmsg, "type light");
  }
  else if (frame == DARK)
  {
    sprintf(ccdmsg, "type dark");
  }
  else if (frame == BIAS)
  {
    sprintf(ccdmsg, "type bias");
  }  
  else if (frame == FLAT)  
  {
    sprintf(ccdmsg, "type flat");
  }
  else
  {
    return;
  }  
  
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}


void ccd_receive_type(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char new_type[64];
  
  j=0;
  nresponses = XPAGet(NULL, "ccd", "type", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j=sscanf(data_buffer[i],"%s", new_type);
      
      if (j == 1)
      {
        if( !strcmp(new_type, "light") )
        {
          frame = LIGHT;
        }
        else if( !strcmp(new_type, "dark") )
        {
          frame = DARK;
        }
        else if( !strcmp(new_type, "bias") )
        {
          frame = BIAS;
        }
	else if( !strcmp(new_type, "flat") )
	{
	  frame = FLAT;
	}  
      }  
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}

void ccd_send_number(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
  
  /* Send the requested data */
  
  sprintf(ccdmsg, "number %d", image_number);
  
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}

void ccd_receive_number(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  int new_number;
  
  j=0;
  nresponses = XPAGet(NULL, "ccd", "number", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j=sscanf(data_buffer[i],"%d", &new_number);
      
      if (j == 1)
      {
           image_number = new_number;
      }  
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}

void ccd_send_multicount(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
  
  /* Send the requested data */
  
  sprintf(ccdmsg, "multicount %d", frame_count_multi);
  
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}

void ccd_receive_multicount(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  int new_multicount;
  
  j=0;
  nresponses = XPAGet(NULL, "ccd", "multicount", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j=sscanf(data_buffer[i],"%d", &new_multicount);
      
      if (j == 1)
      {
           frame_count_multi = new_multicount;
      }  
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}

void ccd_send_temperature(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
  
  /* Send the requested data */
  
  sprintf(ccdmsg, "temperature %lf", setpoint);
  
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}


void ccd_receive_temperature(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  double new_temperature;
  double new_setpoint;
  double new_cooler_power;
  
  j=0;
  nresponses = XPAGet(NULL, "ccd", "temperature", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j=sscanf(data_buffer[i],"%lf %lf %lf", &new_temperature, &new_setpoint,
        &new_cooler_power);
      
      if (j == 3)
      {
        temperature = new_temperature;
        setpoint = new_setpoint;
        cooler_power = new_cooler_power;
      }  
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}

void ccd_send_file(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
  
  /* Send the requested data */
  
  sprintf(ccdmsg, "file %s", base_name);
  
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}

void ccd_receive_file(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char new_base_name[64];
  char new_file_name[64];
    
  j=0;
  nresponses = XPAGet(NULL, "ccd", "file", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j=sscanf(data_buffer[i],"%s %s", new_base_name, new_file_name);
      
      if (j == 2)
      {
        strncpy(base_name, new_base_name, 64);
        strncpy(file_name, new_file_name, 64);
      }  
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}

void ccd_send_target(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
  
  /* Send the requested data */
  
  snprintf(ccdmsg, 64, "target %s", fits_target);
  
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}


void ccd_receive_target(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char new_fits_target[64];
    
  j=0;
  nresponses = XPAGet(NULL, "ccd", "target", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j=sscanf(data_buffer[i],"%s", new_fits_target);
      
      if (j == 1)
      {
        strncpy(fits_target, new_fits_target, 64);
      }  
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}

void ccd_send_telescope(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
  
  /* Send the requested data */
  
  sprintf(ccdmsg, "telescope %s", fits_telescope);
  
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}


void ccd_receive_telescope(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char new_fits_telescope[64];
    
  j=0;
  nresponses = XPAGet(NULL, "ccd", "telescope", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j=sscanf(data_buffer[i],"%s", new_fits_telescope);
      
      if (j == 1)
      {
        strncpy(fits_telescope, new_fits_telescope, 64);
      }  
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}

void ccd_send_instrument(void)
{
  #define NXPA 10
  int i, nresponses;
  size_t buffer_length = 0;
  char *data_buffer = NULL;
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char ccdmsg[64];
  
  /* Send the requested data */
  
  sprintf(ccdmsg, "instrument %s", fits_instrument);
  
  nresponses = XPASet(NULL, "ccd", ccdmsg, NULL, data_buffer,
    buffer_length, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] != NULL )
    {
    
      /* Process error messages */
    
      printf("%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free(server_names[i]);
    }
    if( server_messages[i] )
    { 
     free(server_messages[i]);  
    }
  }
}


void ccd_receive_instrument(void)
{  
  #define NXPA 10
  int i, j, nresponses;
  size_t buffer_lengths[NXPA]={0};
  char *data_buffer[NXPA]; 
  char *server_names[NXPA];
  char *server_messages[NXPA];
  char new_fits_instrument[64];
    
  j=0;
  nresponses = XPAGet(NULL, "ccd", "instrument", NULL, data_buffer, 
    buffer_lengths, server_names, server_messages, NXPA);
  
  for(i=0; i < nresponses; i++)
  {
    if( server_messages[i] == NULL )
    {          
      j=sscanf(data_buffer[i],"%s", new_fits_instrument);
      
      if (j == 1)
      {
        strncpy(fits_instrument, new_fits_instrument, 64);
      }  
    }
    else
    {
    
      /* Process error messages */
    
      fprintf(stderr,"%s (%s)\n", server_messages[i], server_names[i]);
    
    }
    if( server_names[i] )
    {  
      free( server_names[i] );
    }
    if( server_messages[i] )
    { 
     free( server_messages[i] );  
    }
  }
  return;
}

