/*telpos.c - works with telpos.tcl to get telescope
  position from PC Guider and tell it to HQ
  All we really do here is provide the actual serial
  I/O for the tcl program to call

Version 1.00 Written Nov97 - SJK

1.00 SJK - placed in operation at BBSO 1Dec97
*/

#include<stdio.h>
#include<tcl.h>
#include<tk.h>
/* these 4 are for serial port control */
#include<unistd.h>  /* UNIX standard function defs */
#include<fcntl.h>   /* File control definitions */
#include<errno.h>   /* Error number definitions */
#include<termios.h> /* POSIX terminal control definitions */

 /*initialize serial port for PC Guider*/
int initialize_serial(void);

 /*read a string from a serial port*/
int serial_in (int sfd, char *string);

  /*send a string out a serial port*/
int serial_out (int sfd, char *string);

 /*initialize tcl/tk GUI*/
int tcl_initialize(Tcl_Interp *interp);

 /*get currnent position from PC Guider*/
int t_getpos(ClientData cd, Tcl_Interp *interp, int argc, char **argv);

Tcl_Interp *Interp;     /*the Tcl/Tk GUI interface*/
int Sfd;                /*serial file descriptor for PC Guider serial port*/

/*MAIN*/
main()
    {
    int err;

    /*initialize serial port*/
    err=initialize_serial();    
    if (err==-1)
        {
        printf("Can't open serial port for PC Guider communications.\n");
        printf("Make sure you are running on Ingrid and serial port is connected\n");
        exit (1);
        /*ZZZ uncomment that when running for real*/
        }

    /*set up Tcl/Tk GUI*/
    Interp=Tcl_CreateInterp();
 
    if (err=tcl_initialize(Interp))
        return(err);

    /*since I have an update loop in the .tcl file, I never reach
      this part of the program unless I get an err above or maybe
      when I quit the GUI*/

    return(0);

    }

/*INITIALIZE_SERIAL*/
/* set up the serial port to talk to the PC Guider
   it is connected to /dev/ttyC7
   called by main()
   calls serial_in()
   returns 0 if ok
          -1 if can't open serial port
*/
int initialize_serial()
    {
    struct termios sopts; /*serial port options*/
    char buffer[80]; /*used to flush input serial buffer*/

    if ((Sfd=open("/dev/ttyC7",O_RDWR | O_NOCTTY | O_NDELAY)) == -1)
        return(-1);

    /*set serial parameters*/
    /*make read return 0 bytes if none available*/
    fcntl(Sfd, F_SETFL, FNDELAY);

    /*First, get current parameters*/
    tcgetattr(Sfd, &sopts);

    /*turn off echo*/
    sopts.c_lflag &= ~(ECHO);

    /*set canonical (line at a time mode)*/
    sopts.c_lflag |= ICANON;

    /*maps input CR to NL*/
    sopts.c_iflag |= ICRNL;
    sopts.c_iflag &= ~(IGNCR);
    sopts.c_iflag &= ~(INLCR);

    /*accept \r as EOL in addition to \n*/
    sopts.c_cc[VEOL]='\r';

    /*turn on output processing so other o_flags have an effect*/
    sopts.c_oflag |= (OPOST);
    /*allow me to send a CR instead of NL if I want*/
    sopts.c_oflag &= ~ONLRET;
    sopts.c_oflag &= ~ONLCR;

    sopts.c_oflag &= ~OCRNL;

    /*now baud rates*/
    cfsetispeed(&sopts,B9600);
    cfsetospeed(&sopts,B9600);
    /* now set to 8N1 */
    sopts.c_cflag &= ~CSIZE;
    sopts.c_cflag |= CS8;
    sopts.c_cflag &= ~PARENB;
    sopts.c_cflag &= ~CSTOPB;

    /*turn off hardware flow control*/
    sopts.c_cflag &= ~CRTSCTS;
    /*turn off software flow control on input and output*/
    sopts.c_iflag &= ~IXON;
    sopts.c_iflag &= ~IXOFF;

    /*make these settings active now*/
    tcsetattr(Sfd, TCSANOW, &sopts);

    /*Clear/flush the input buffer*/
    while(serial_in(Sfd,buffer)>0);

    return(0);
    }

/*SERIAL_IN*/
/* function serial_in reads a string from the given
   serial port (described by its file descriptor).
   it will read a max of 80 bytes
   returns # bytes read or the error number
   called by serial_initialize()
             t_getpos()
*/
int serial_in (int sfd, char *string)

    {
    int n=0;

    if ((n=read(sfd,string,80))>0)
        string[n]='\0';
    /*uncomment the previous two lines and delete
      the next two for real operations*/
    /*strcpy(string,"OK\n");*/
    /*n=4;*/
    return (n);
    }

/*SERIAL_OUT*/
/* function serial_out sends the given string out the
   given serial port (described by its file descriptor)
   returns the # of bytes written or the err value
             t_getpos()
*/
int serial_out (int sfd, char *string)

    {
    int n;
    int err;
    char s[80];

    /*n=strlen(string);*/
    /*printf("SERIAL_OUT:%s\n",string);*/
    /*err=10;*/
    /*use the above 3 lines for testing and the below 2 for real*/
    if ((err=write(sfd,string,n))<0)
        fprintf(stderr,"serial port write failed: %s\n",string);

    return(err);
    }

/*TCL_INITIALIZE*/
/* procedure tcl_initialize starts up the Tcl/Tk GUI. The
   code for which is in ./telpos.tcl
   called by main()
   returns -1 if failed
           0 otherwise
*/
int tcl_initialize(Tcl_Interp *interp)

    {

    if (Tcl_Init(interp) == TCL_ERROR)
         {
         fprintf(stderr, "Tcl_Init failed: %s\n",interp->result);
         return(-1);
         }

    if (Tk_Init(interp) == TCL_ERROR)
         {
         fprintf(stderr, "Tk_Init failed: %s\n",interp->result);
         return(-1);
         }

    /*create new commands which Tcl/Tk GUI will call*/

    /*get and return current position*/
    Tcl_CreateCommand (interp, "Cgetpos", (Tcl_CmdProc *) t_getpos,
                       (ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL);

    /*tell Tcl/Tk which file to execute*/
    Tcl_EvalFile(interp,"./telpos.tcl");

    return(0);
    }

/*T_GETPOS*/
/*read current telescope positions from PC Guider
  called by telpos.tcl
  calls serial_out()
  serial_in()
  returns X10 Y10 X26 Y26
*/
int t_getpos (ClientData cd, Tcl_Interp *interp, int argc, char **argv)
    {
    char s[80];            /*command sent to/response from  PC Guider*/
    float x10,y10,x26,y26; /*X and Y coords for 10 and 26*/
    int serr=0;              /*return value form serial_out and _in*/
    
    while (serr!=34)  /*34 chars is the right response length for an atrp
                        command*/
        {
        /*send report position command to PC Guider*/ 
        sprintf(s,"atrp\n");
        serr=serial_out(Sfd,s);
        /*XXX do something with serr*/
        /*wait for command response*/
        while ((serr=serial_in(Sfd,s))<=0); /*XXXadd a timeout?*/
        if (serr!=34) printf("XXXtelpos got %s\n",s);
        }

    sscanf (s,"P %f %f %f %f",&y10,&x10,&y26,&x26);
    sprintf(interp->result,"%f %f %f %f",x10,y10,x26,y26);
    return(TCL_OK);
    }
