/*--------------------------------------------------------------------------

	Some code to connect to a serial port through the SINQ system.
	
	Just a wrapper around serialsinq derived from David Maden's
	EL734 routines.
	
	You are free to use and modify this software for noncommercial
	usage.
	
	No warranties or liabilities of any kind taken by me or my employer
	
	Very primitive device to send commands to a motor from Tcl
	
	Modified version for use within SICS.
----------------------------------------------------------------------------*/
#include "sinq_prototypes.h"
/* #include <timers.h>*/
#include <sics.h>
#include <tcl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "rs232c_def.h"
#include "el734_def.h"
#include "hardsup/serialsinq.h"

#define False 0
#define True 1

/*---------------------------------------------------------------------------
	Tcl has a high niceness level. It deletes a command properly when
	exiting, reinitializing etc. I use this facility to kill off the
	motor initialised in Controller.
---------------------------------------------------------------------------*/
EXTERN void SerialMurder(ClientData pData)
{
  if (pServ->pReader != NULL) {
    NetReadRemoveUserSocket(pServ->pReader, SerialGetSocket(&(pData)));
  }
  SerialClose(&(pData));
  free(pData);
}

/*------------------  a forward declaration -----------------------------*/
EXTERN int SurielSend(ClientData clientData, Tcl_Interp * interp,
                      int argc, char *argv[]);

/*----------------------------------------------------------------------------
	Controller is the main entry point for this stuff. It connects to a motor
	and, on success, creates a new command with the name of the motor.
	Syntax:
		Controller  name host port channel 
---------------------------------------------------------------------------*/

int Controller(ClientData clientData, Tcl_Interp * interp,
               int argc, char *argv[])
{
  int iRet;
  int iPort, iChannel, iMotor;
  char *pErr = NULL;
  char pBueffel[80];
  void **pData = NULL;

  /* check arguments */
  if (argc < 5) {
    Tcl_AppendResult(interp,
                     " Insufficient arguments: Controller name host port channel index",
                     (char *) NULL);
    return TCL_ERROR;
  }

  /* convert arguments */
  iRet = Tcl_GetInt(interp, argv[3], &iPort);
  if (iRet == TCL_ERROR) {
    Tcl_AppendResult(interp, "Need integer value for port", (char *) NULL);
    return iRet;
  }

  iRet = Tcl_GetInt(interp, argv[4], &iChannel);
  if (iRet == TCL_ERROR) {
    Tcl_AppendResult(interp, "Need integer value for channel",
                     (char *) NULL);
    return iRet;
  }

  iMotor = 1;


  /* make a new pointer, initialise EL734st */
  pData = malloc(sizeof(void *));
  if (pData == NULL) {
    Tcl_AppendResult(interp, "No memory in SerialSinq", NULL);
    return TCL_ERROR;
  }

  /* check for optional force flag */
  if (argc > 5) {
    iRet = SerialForceOpen(pData, (char *) argv[2], iPort, iChannel);
  }

  /* open the motor, finally */
  iRet = SerialOpen(pData, (char *) argv[2], iPort, iChannel);
  if (iRet == 1) {              /* success */
    /* handle TCL, create new command: the serial line */
    Tcl_CreateCommand(interp, strdup(argv[1]), SurielSend,
                      *pData, SerialMurder);
    strcpy(pBueffel, argv[1]);
    Tcl_AppendResult(interp, strdup(argv[1]), (char *) NULL);
    if (pServ->pReader != NULL) {
      NetReadRegisterUserSocket(pServ->pReader, SerialGetSocket(pData));
    }
    return TCL_OK;
  } else {
    SerialError(iRet, pBueffel, 79);
    Tcl_AppendResult(interp, pBueffel, (char *) NULL);
    SerialClose(pData);
    free(pData);
    return TCL_ERROR;
  }
}

/*--------------------------------------------------------------------------
  Now, this interprets some commands: 
          -tmo val 
                   will set a timeout value for the connection. Everything 
                   else will be concatenated and sent to the device.
          -sendterm text 
                    defines the terminator which will be appended automatically
                    to each command.
          -replyterm text
                    sets the expected reply terminator from the Macintosh
                    Serial Port server.                    

----------------------------------------------------------------------------*/
EXTERN int SurielSend(ClientData clientData, Tcl_Interp * interp,
                      int argc, char *argv[])
{
  char pBueffel[256];
  char pAnswer[256];
  char *pErr = NULL;
  int iRet, iMSR;
  int i;
  void *pData;

  pData = clientData;

  if (argc >= 2) {
    if (strcmp(argv[1], "-tmo") == 0) {
      if (argc >= 3) {
        iRet = Tcl_GetInt(interp, argv[2], &iMSR);
        if (iRet != TCL_OK) {
          sprintf(pBueffel, "%s is not a valid number", argv[2]);
          Tcl_AppendResult(interp, pBueffel, NULL);
          return TCL_ERROR;
        }
        SerialConfig(&(pData), iMSR);
        return TCL_OK;
      } else {
        Tcl_AppendResult(interp, "Expected parameter after -tmo", NULL);
        return TCL_ERROR;
      }
    } else if (strcmp(argv[1], "-sendterm") == 0) {
      if (argc < 3) {
        Tcl_AppendResult(interp, "Expected parameter after -tmo", NULL);
        return TCL_ERROR;
      }
      iRet = SerialSendTerm(&(pData), (char *) argv[2]);
      if (iRet != 1) {
        Tcl_AppendResult(interp, "To many characters for terminator",
                         NULL);
        return TCL_ERROR;
      }
      return TCL_OK;
    } else if (strcmp(argv[1], "-replyterm") == 0) {
      if (argc < 3) {
        Tcl_AppendResult(interp, "Expected parameter after -tmo", NULL);
        return TCL_ERROR;
      }
      iRet = SerialATerm(&(pData), (char *) argv[2]);
      if (!iRet) {
        Tcl_AppendResult(interp, "To many characters for terminator",
                         NULL);
        return TCL_ERROR;
      }
      return TCL_OK;
    } else if (strcmp(argv[1], "-put") == 0) {
      NetReadResetUser(pServ->pReader, SerialGetSocket(&(pData)));
      if (argc > 2) {
        strcpy(pBueffel, argv[2]);
      }
      for (i = 3; i < argc; i++) {
        strcat(pBueffel, " ");
        strcat(pBueffel, argv[i]);
      }
      iRet = SerialSend(&(pData), pBueffel);
      if (iRet != 1) {
        Tcl_AppendResult(interp, pAnswer, NULL);
        return TCL_ERROR;
      }
      return TCL_OK;
    } else if (strcmp(argv[1], "-readable") == 0) {
      iRet = NetReadReadable(pServ->pReader, SerialGetSocket(&(pData)));
      if (iRet) {
        Tcl_AppendResult(interp, "1", NULL);
        return TCL_OK;
      } else {
        Tcl_AppendResult(interp, "0", NULL);
        return TCL_OK;
      }
    } else if (strcmp(argv[1], "-get") == 0) {
      if (NetReadReadable(pServ->pReader, SerialGetSocket(&(pData)))) {
        iRet = SerialReceive(&(pData), pAnswer, 255);
        Tcl_AppendResult(interp, pAnswer, NULL);
        if (iRet == 1) {
          return TCL_OK;
        } else {
          return TCL_ERROR;
        }
      }
      Tcl_AppendResult(interp, "Not Readable", NULL);
      return TCL_ERROR;
    }
  }


  if (argc >= 2) {
    strcpy(pBueffel, argv[1]);
  }
  for (i = 2; i < argc; i++) {
    strcat(pBueffel, " ");
    strcat(pBueffel, argv[i]);
  }
  i = strlen(pBueffel);
  iRet = SerialWriteRead(&(pData), pBueffel, pAnswer, 254);
  if (iRet != 1) {
    Tcl_AppendResult(interp, pAnswer, NULL);
    return TCL_ERROR;
  }
  Tcl_AppendResult(interp, pAnswer, NULL);
  return TCL_OK;
}
