 /*--------------------------------------------------------------------------
                     S L S V M E

 This file contains the driver for the PSI-DSP magnet controller as
 aquired from SLS.

 This version is for the new interface provided by the vmemaggi server 
 program running on embedded linux on a computer in the VME crate which
 talks directly to the IP communication mudules on the VME bus.  
 
 Copyright: see file COPYRIGHT
 
 Mark Koennecke, April 2008
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <assert.h>
#include <unistd.h>
#include <fortify.h>
#include <conman.h>
#include <servlog.h>
#include <fortify.h>
#include <sics.h>
#include "evdriver.h"
#include <network.h>
#include <rs232controller.h>
#include "vmemaggi.h"
#include <stptok.h>

#define ABS(x) (x < 0 ? -(x) : (x)) 
extern char *trim(char *txt);

#define DEVERR       -2001
#define BADHIGHLIM   -2002
#define BADLOWLIM    -2003
/*-----------------------------------------------------------------------*/
  typedef struct {
                   prs232 controller;
                   int iNum;
                   int iError;
                   int iDevError;
                   char errorText[80];
                  } SLSDriv, *pSLSDriv;
/*-------------------------------------------------------------------------*/
static int communicateSLS(pSLSDriv self, char *command, 
		char *reply, int replyLen)
{
  long lVal = 0;
  int iRet, i, address, status;
  char *pPtr;
  char text[80];
  
  if(!self->controller){
	  self->iError = NOTCONNECTED;
	  strcpy(self->errorText,"Not Connected");
	  return -1;
  }
  self->iDevError = 0;
  
  memset(reply,0,replyLen);
  iRet = transactRS232(self->controller, command, strlen(command),
		  reply, replyLen);
  if(iRet < 0){
	  return iRet;
  }
  if(strstr(reply, "ERROR") != NULL){
	  pPtr = reply;
	  /* jump over error */
	  pPtr = stptok(pPtr,"text",80,":");
	  /* read error number */
	  pPtr = stptok(pPtr,"text",80,":");
	  self->iError = atoi(trim(text));
	  /* read error description */
	  pPtr = stptok(pPtr,"text",80,":");
	  strncpy(self->errorText, text, 80);
	  return DEVERR;
  }
  return 1;
}
/*--------------------------------------------------------------------------*/
static void locateValue(char *rawReply, char *value, int valLen){
	char *pPtr;
	
	pPtr = rawReply;
	pPtr = stptok(pPtr,value, valLen," ");
	pPtr = stptok(pPtr,value, valLen," ");
	stptok(pPtr,value, valLen," ");
}
 /*---------------------------------------------------------------------*/
static void slsdspCodeToText(int code, char *text, int textlen){
  switch(code){
   case 0x0:
     strncpy(text,"NO",textlen);
     break;
   case 0x1:
     strncpy(text,"DEVICE_STATE_ERROR",textlen);
     break;
   case 0x2:
     strncpy(text,"DEVICE_SUPERVISOR_DISABLED",textlen);
     break;
   case 0x3:
     strncpy(text,"COMMAND_ABORT",textlen);
     break;
   case 0x4:
     strncpy(text,"DATA_NOT_STORED",textlen);
     break;
   case 0x5:
     strncpy(text,"ERROR_ERASING_FLASH",textlen);
     break;
   case 0x6:
     strncpy(text,"COMMUNICATION_BREAK",textlen);
     break;
   case 0x7:
     strncpy(text,"INTERNAL_COMMUNICATION_ERROR",textlen);
     break;
   case 0x8:
     strncpy(text,"MASTER_CARD_ERROR",textlen);
     break;
   case 0x9:
     strncpy(text,"INTERNAL_BUFFER_FULL",textlen);
     break;
   case 0xa:
     strncpy(text,"WRONG_SECTOR",textlen);
     break;
   case 0xb:
     strncpy(text,"DATA_NOT_COPIED",textlen);
     break;
   case 0xc:
     strncpy(text,"WRONG_DOWNLOAD_PARAMETERS",textlen);
     break;
   case 0xd:
     strncpy(text,"DEVICE_PARAMETRIZATION_ERROR",textlen);
     break;
   case 0x10:
     strncpy(text,"TIMEOUT_DC_LINK_VOLTAGE",textlen);
     break;
   case 0x11:
     strncpy(text,"TIMEOUT_AUXILIARY_RELAY_ON",textlen);
     break;
   case 0x12:
	   strncpy(text,"TIMEOUT_AUXILIARY_RELAY_OFF",textlen);
     break;
   case 0x13:
     strncpy(text,"TIMEOUT_MAIN_RELAY_ON",textlen);
     break;
   case 0x14:
     strncpy(text,"TIMEOUT_MAIN_RELAY_OFF",textlen);
     break;
   case 0x15:
     strncpy(text,"TIMEOUT_DATA_DOWNLOAD",textlen);
     break;
   case 0x20:
     strncpy(text,"INTERLOCK",textlen);
     break;
   case 0x21:
     strncpy(text,"MASTER_SWITCH",textlen);
     break;
   case 0x22:
     strncpy(text,"MAGNET_INTERLOCK",textlen);
     break;
   case 0x23:
     strncpy(text,"TEMPERATURE_TRANSFORMER",textlen);
     break;
   case 0x24:
     strncpy(text,"TEMPERATURE_RECTIFIER",textlen);
     break;
   case 0x25:
     strncpy(text,"TEMPERATURE_CONVERTER",textlen);
     break;
   case 0x26:
     strncpy(text,"CURRENT_TRANSDUCER",textlen);
     break;
   case 0x27:
     strncpy(text,"TEMPERATURE_POLARITY_SWITCH",textlen);
     break;
   case 0x28:
     strncpy(text,"POWER_SEMICONDUCTOR",textlen);
     break;
   case 0x29:
     strncpy(text,"MAIN_RELAY",textlen);
     break;
   case 0x2a:
     strncpy(text,"AD_CONVERTER_CARD",textlen);
     break;
   case 0x2b:
     strncpy(text,"POLARITY_SWITCH",textlen);
     break;
   case 0x2c:
     strncpy(text,"AUXILIARY_RELAY",textlen);
     break;
   case 0x2d:
     strncpy(text,"MASTER_SWITCH_T1",textlen);
     break;
   case 0x2e:
     strncpy(text,"MASTER_SWITCH_T2",textlen);
     break;
   case 0x2f:
     strncpy(text,"TEMPERATURE_MAGNET",textlen);
     break;
   case 0x30:
     strncpy(text,"WATER_MAGNET",textlen);
     break;
   case 0x31:
     strncpy(text,"WATER_RACK",textlen);
     break;
   case 0x40:
     strncpy(text,"LOAD_CURRENT_TOO_HIGH",textlen);
     break;
   case 0x41:
     strncpy(text,"DC_LINK_VOLTAGE_TOO_LOW",textlen);
     break;
   case 0x42:
     strncpy(text,"DC_LINK_VOLTAGE_TOO_HIGH",textlen);
     break;
   case 0x43:
     strncpy(text,"LOAD_VOLTAGE_TOO_HIGH",textlen);
     break;
   case 0x44:
     strncpy(text,"LOAD_CURRENT_RIPPLE_TOO_HIGH",textlen);
     break;
   case 0x45:
     strncpy(text,"DC_LINK_ISOLATION_NOT_OK",textlen);
     break;
   case 0x46:
     strncpy(text,"LOAD_ISOLATION_NOT_OK",textlen);
     break;
   case 0x47:
     strncpy(text,"LOAD_IMPEDANCE_OUT_OF_RANGE",textlen);
     break;
   case 0x48:
     strncpy(text,"SHUT_OFF_CURRENT_TOO_HIGH",textlen);
     break;
   case 0x49:
     strncpy(text,"LOAD_DC_CURRENT_TOO_HIGH",textlen);
     break;
   case 0x4a:
     strncpy(text,"CURRENT_I1A1_TOO_HIGH",textlen);
     break;
   case 0x4b:
     strncpy(text,"CURRENT_I1B1_TOO_HIGH",textlen);
     break;
   case 0x4c:
     strncpy(text,"CURRENT_I1A2_TOO_HIGH",textlen);
     break;
   case 0x4d:
     strncpy(text,"CURRENT_I1B2_TOO_HIGH",textlen);
     break;
   case 0x4e:
     strncpy(text,"CURRENT_I2A1_TOO_HIGH",textlen);
     break;
   case 0x4f:
     strncpy(text,"CURRENT_I2B1_TOO_HIGH",textlen);
     break;
   case 0x50:
     strncpy(text,"CURRENT_I2A2_TOO_HIGH",textlen);
     break;
   case 0x51:
     strncpy(text,"CURRENT_I2B2_TOO_HIGH",textlen);
     break;
   case 0x52:
     strncpy(text,"CURRENT_I3P_TOO_HIGH",textlen);
     break;
   case 0x53:
     strncpy(text,"CURRENT_I3N_TOO_HIGH",textlen);
     break;
   case 0x54:
     strncpy(text,"CURRENT_IE_TOO_HIGH",textlen);
     break;
   case 0x55:
     strncpy(text,"VOLTAGE_U1A_TOO_LOW",textlen);
     break;
   case 0x56:
     strncpy(text,"VOLTAGE_U1B_TOO_LOW",textlen);
     break;
   case 0x57:
     strncpy(text,"DIFF_CURRENT_I1A1_I1A2_TOO_HIGH",textlen);
     break;
   case 0x58:
     strncpy(text,"DIFF_CURRENT_I1B1_I1B2_TOO_HIGH",textlen);
     break;
   case 0x59:
     strncpy(text,"DIFF_CURRENT_I2A1_I2A2_TOO_HIGH",textlen);
     break;
   case 0x5a:
     strncpy(text,"DIFF_CURRENT_I2B1_I2B2_TOO_HIGH",textlen);
     break;
   case 0x5b:
     strncpy(text,"DIFF_CURRENT_I3P_I3N_TOO_HIGH",textlen);
     break;
   case 0x5c:
     strncpy(text,"CURRENT_I1A_TOO_HIGH",textlen);
     break;
   case 0x5d:
     strncpy(text,"CURRENT_I1B_TOO_HIGH",textlen);
     break;
   case 0x5e:
     strncpy(text,"CURRENT_I3A1_TOO_HIGH",textlen);
     break;
   case 0x5f:
     strncpy(text,"CURRENT_I3B1_TOO_HIGH",textlen);
     break;
   case 0x60:
     strncpy(text,"CURRENT_I3A2_TOO_HIGH",textlen);
     break;
   case 0x61:
     strncpy(text,"CURRENT_I3B2_TOO_HIGH",textlen);
     break;
   case 0x62:
     strncpy(text,"CURRENT_I4_TOO_HIGH",textlen);
     break;
   case 0x63:
     strncpy(text,"CURRENT_I5_TOO_HIGH",textlen);
     break;
   case 0x64:
     strncpy(text,"DIFF_CURRENT_I3A1_I3A2_TOO_HIGH",textlen);
     break;
   case 0x65:
     strncpy(text,"DIFF_CURRENT_I3B1_I3B2_TOO_HIGH",textlen);
     break;
   case 0x66:
     strncpy(text,"DIFF_CURRENT_I4_I5_TOO_HIGH",textlen);
     break;
   case 0x67:
     strncpy(text,"VOLTAGE_U3A_TOO_LOW",textlen);
     break;
   case 0x68:
     strncpy(text,"VOLTAGE_U3B_TOO_LOW",textlen);
     break;
   case 0x69:
     strncpy(text,"VOLTAGE_U1_TOO_LOW",textlen);
     break;
   case 0x6a:
     strncpy(text,"VOLTAGE_U3A_TOO_HIGH",textlen);
     break;
   case 0x6b:
     strncpy(text,"VOLTAGE_U3B_TOO_HIGH",textlen);
     break;
   case 0x6c:
     strncpy(text,"SPEED_ERROR_TOO_HIGH",textlen);
     break;
   case 0x70:
     strncpy(text,"MAIN_RELAY_A",textlen);
     break;
   case 0x71:
     strncpy(text,"MAIN_RELAY_B",textlen);
     break;
   case 0x72:
     strncpy(text,"POWER_SWITCH_A",textlen);
     break;
   case 0x73:
     strncpy(text,"POWER_SWITCH_B",textlen);
     break;
   case 0x74:
     strncpy(text,"MONITOR_TRAFO_A",textlen);
     break;
   case 0x75:
     strncpy(text,"MONITOR_TRAFO_B",textlen);
     break;
   case 0x76:
     strncpy(text,"TEMPERATURE_RECTIFIER_A",textlen);
     break;
   case 0x77:
     strncpy(text,"TEMPERATURE_RECTIFIER_B",textlen);
     break;
   case 0x78:
     strncpy(text,"TEMPERATURE_CONVERTER_A",textlen);
     break;
   case 0x79:
     strncpy(text,"TEMPERATURE_CONVERTER_B",textlen);
     break;
   case 0x7a:
     strncpy(text,"TEMPERATURE_CONVERTER_A1",textlen);
     break;
   case 0x7b:
     strncpy(text,"TEMPERATURE_CONVERTER_B1",textlen);
     break;
   case 0x7c:
     strncpy(text,"TEMPERATURE_CONVERTER_A2",textlen);
     break;
   case 0x7d:
     strncpy(text,"TEMPERATURE_CONVERTER_B2",textlen);
     break;
   case 0x7e:
     strncpy(text,"TEMPERATURE_TRANSFORMER_A",textlen);
     break;
   case 0x7f:
     strncpy(text,"TEMPERATURE_TRANSFORMER_B",textlen);
     break;
   case 0x80:
     strncpy(text,"WATER_RECTIFIER_A",textlen);
     break;
   case 0x81:
     strncpy(text,"WATER_RECTIFIER_B",textlen);
     break;
   case 0x82:
     strncpy(text,"WATER_CONVERTER_A",textlen);
     break;
   case 0x83:
     strncpy(text,"WATER_CONVERTER_B",textlen);
     break;
   case 0x84:
     strncpy(text,"WATER_CONVERTER_A1",textlen);
     break;
   case 0x85:
     strncpy(text,"WATER_CONVERTER_B1",textlen);
     break;
   case 0x86:
     strncpy(text,"WATER_CONVERTER_A2",textlen);
     break;
   case 0x87:
     strncpy(text,"WATER_CONVERTER_B2",textlen);
     break;
   case 0x88:
     strncpy(text,"WATER_TRANSFORMER_A",textlen);
     break;
   case 0x89:
     strncpy(text,"WATER_TRANSFORMER_B",textlen);
     break;
   case 0x8a:
     strncpy(text,"DOOR_A",textlen);
     break;
   case 0x8b:
     strncpy(text,"DOOR_B",textlen);
     break;
   case 0x8c:
     strncpy(text,"DOOR_C",textlen);
     break;
   case 0x8d:
     strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_A",textlen);
     break;
   case 0x8e:
     strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_B",textlen);
     break;
   case 0x8f:
     strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_A1",textlen);
     break;
   case 0x90:
     strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_B1",textlen);
     break;
   case 0x91:
     strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_A2",textlen);
     break;
   case 0x92:
     strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_B2",textlen);
     break;
   case 0x93:
     strncpy(text,"CURRENT_TRANSDUCER_I3P",textlen);
     break;
   case 0x94:
     strncpy(text,"CURRENT_TRANSDUCER_I3N",textlen);
     break;
   case 0x95:
     strncpy(text,"MAGNET_INTERLOCK_1",textlen);
     break;
   case 0x96:
     strncpy(text,"MAGNET_INTERLOCK_2",textlen);
     break;
   case 0x97:
     strncpy(text,"VENTILATOR",textlen);
     break;
   case 0x98:
     strncpy(text,"EMERGENCY_SWITCH",textlen);
     break;
   case 0x99:
     strncpy(text,"CAPACITOR_DISCHARGE_A_ON",textlen);
     break;
   case 0x9a:
     strncpy(text,"CAPACITOR_DISCHARGE_B_ON",textlen);
     break;
   case 0x9b:
     strncpy(text,"CURRENT_TRANSDUCER_I4",textlen);
     break;
   case 0x9c:
     strncpy(text,"CURRENT_TRANSDUCER_I5",textlen);
     break;
   case 0xb0:
     strncpy(text,"TIMEOUT_DC_LINK_VOLTAGE_PART_A",textlen);
     break;
   case 0xb1:
     strncpy(text,"TIMEOUT_DC_LINK_VOLTAGE_PART_B",textlen);
     break;
   case 0xb2:
     strncpy(text,"TIMEOUT_AUXILIARY_RELAY_A_ON",textlen);
     break;
   case 0xb3:
     strncpy(text,"TIMEOUT_AUXILIARY_RELAY_B_ON",textlen);
     break;
   case 0xb4:
     strncpy(text,"TIMEOUT_AUXILIARY_RELAY_A_OFF",textlen);
     break;
   case 0xb5:
     strncpy(text,"TIMEOUT_AUXILIARY_RELAY_B_OFF",textlen);
     break;
   case 0xb6:
     strncpy(text,"TIMEOUT_MAIN_RELAY_A_ON",textlen);
     break;
   case 0xb7:
     strncpy(text,"TIMEOUT_MAIN_RELAY_B_ON",textlen);
     break;
   case 0xb8:
     strncpy(text,"TIMEOUT_MAIN_RELAY_A_OFF",textlen);
     break;
   case 0xb9:
     strncpy(text,"TIMEOUT_MAIN_RELAY_B_OFF",textlen);
     break;
  }
}
/*---------------------------------------------------------------------------*/
  static int GetSLSPos(pEVDriver  self, float *fPos)
  {
     pSLSDriv pMe = NULL;
     char command[40], reply[132], value[40];
     int iRet;
     
     assert(self);
     pMe = (pSLSDriv)self->pPrivate;
     assert(pMe);
     
     /*
      * first try to read the error code
      */
     snprintf(command,40,"r %d err\n", pMe->iNum);
     iRet = communicateSLS(pMe, command, reply, 132);
     if(iRet < 0){
    	 return 0;
     }
     locateValue(reply, value,40);
     sscanf(value,"%x", &iRet);
     if(iRet != 0){
    	 slsdspCodeToText(iRet, pMe->errorText, 80);
    	 pMe->iError = DEVERROR;
    	 pMe->iDevError = iRet;
    	 return 0;
     }
     
     /*
      * really read the current
      */
     snprintf(command,40,"r %d cur\n", pMe->iNum);
     iRet = communicateSLS(pMe, command, reply, 132);
     if(iRet < 0){
    	 return 0;
     }
     locateValue(reply, value,40);
     sscanf(value,"%f", fPos);
     
     return 1; 	 
  } 
/*----------------------------------------------------------------------------*/
  static int SLSRun(pEVDriver self, float fVal)
  {
     pSLSDriv pMe = NULL;
     int iRet;
     char command[40], reply[132], value[40];
     
     assert(self);
     pMe = (pSLSDriv )self->pPrivate;
     assert(pMe);

     /*
      * first check if this on
      */
     snprintf(command,40,"r %d onoff\n", pMe->iNum);
     iRet = communicateSLS(pMe, command, reply, 132);
     if(iRet < 0){
    	 return 0;
     }
     locateValue(reply,value,40);
     if(strstr(value,"1") == NULL){
    	 /*
    	  * switch on
    	  */
    	 snprintf(command,40,"w %d on\n", pMe->iNum);
         iRet = communicateSLS(pMe, command, reply, 132);
         if(iRet < 0){
        	 return 0;
         }
     }
     
     /*
      * set a new value
      */
     snprintf(command,40,"w %d cur %f\n", pMe->iNum, fVal);
     iRet = communicateSLS(pMe, command, reply, 132);
     if(iRet < 0){
    	 return 0;
     }
     return 1;
 }
 
/*--------------------------------------------------------------------------*/
  static int SLSError(pEVDriver self, int *iCode, char *error, int iErrLen)
  {
     pSLSDriv pMe = NULL;
     char *pPtr = NULL;
     int i1, i2;
     char pBueffel[132];
     
     assert(self);
     pMe = (pSLSDriv)self->pPrivate;
     assert(pMe);

     *iCode = pMe->iError;
      
     if(pMe->iError == DEVERROR){
    	 strncpy(error,pMe->errorText, iErrLen);
    	 return 1;
     }
     if(pMe->iError < -2000 || (pMe->iError >= 70 && pMe->iError < 83)){
    	 strncpy(error,pMe->errorText, iErrLen);
    	 return 1;
     }
     
     getRS232Error(*iCode,error,iErrLen);
    
     return 1;
  }
/*-------------------------------------------------------------------------*/
  static int SLSSend(pEVDriver self, char *pCommand, char *pReply, int iLen)
  {
      pSLSDriv pMe = NULL;
     int iRet, ival;
     char command[40];
 
     assert(self);
     pMe = (pSLSDriv )self->pPrivate;
     assert(pMe);

     if(strcmp(pCommand,"off") == 0){
    	 snprintf(command,40,"w %d off\n", pMe->iNum);
     } else if(strcmp(pCommand,"on") == 0){
    	 snprintf(command,40,"w %d on\n", pMe->iNum);
     } else  {
    	 strncpy(command,pCommand,40);
     }
     iRet = communicateSLS(pMe, command, pReply, iLen);
     if(iRet < 0){
    	 return 0;
     }
    return 1;
  }
/*--------------------------------------------------------------------------*/
  static int SLSInit(pEVDriver self)
  {
     pSLSDriv pMe = NULL;
     int iRet, ival, i;
     char msg[40], reply[40];
     
     assert(self);
     pMe = (pSLSDriv )self->pPrivate;
     assert(pMe);

     iRet = initRS232(pMe->controller);
     if(iRet < 0)
     {
       return 0;
     }
     setRS232SendTerminator(pMe->controller, "\n");
     setRS232ReplyTerminator(pMe->controller, "\n");
     setRS232Timeout(pMe->controller, 1000);
 
     snprintf(msg,40,"w %d on\n", pMe->iNum);
     iRet = communicateSLS(pMe, msg, reply, 40);
     if(iRet < 0){
    	 return 0;
     }

     return 1;
  }  
/*--------------------------------------------------------------------------*/
  static int SLSClose(pEVDriver self)
  {
     pSLSDriv pMe = NULL;
     int iRet, ival;
     char msg[6], reply[6];
     
     assert(self);
     pMe = (pSLSDriv )self->pPrivate;
     assert(pMe);

     closeRS232(pMe->controller);
 
     return 1;
  }  
/*---------------------------------------------------------------------------*/
  static int SLSFix(pEVDriver self, int iError)
  {
     pSLSDriv pMe = NULL;
     int iRet, i, dataLen;
     char buffer[80];
     char msg[6], reply[6];
     float fVal = .0;
     
     assert(self);
     pMe = (pSLSDriv )self->pPrivate;
     assert(pMe);

     switch(iError)
     {
     		case BADHIGHLIM:
     		case BADLOWLIM:
     		case BADSLOT:
     		case BADMAP:
     		case DSPSTOP:
     		case LINKDWN:
     		case MISPS:
     		case PSRNG:
     		case NOPAR:
     		case NOVAL:
     		case BADPAR:
     		case SETRNG:
     		case DEVERROR:
     		      return DEVFAULT;
     		      break;
     		case SOFTTIM:
     		case FPGATIM:
     		case ADDRMIS:
     				return DEVREDO;
     				break;
            case TIMEOUT:
                for(i = 0; i < 10; i++){
                    iRet = availableRS232(pMe->controller);
                    dataLen = 70;
                    if(iRet == 1){
                        readRS232(pMe->controller, buffer,&dataLen);
                    }
                }
                return DEVREDO;
                break;
            default:
                      SLSClose(self);
                      iRet = SLSInit(self);
                      if(iRet)
                      {
                        return DEVREDO;
                      }                 
                      else
                      {
                        return DEVFAULT;
                      }                 
                      break;
     }
  }
     
/*--------------------------------------------------------------------------*/
  static int SLSHalt(pEVDriver *self)
  {
     assert(self);
     
     return 1;
  }
/*------------------------------------------------------------------------*/
  static void KillSLS(void *pData)
  {
     pSLSDriv pMe = NULL;
     
     pMe = (pSLSDriv)pData;
     assert(pMe);
     
      free(pMe);
  }  
/*------------------------------------------------------------------------*/
  pEVDriver CreateSLSVMEDriv(int argc, char *argv[])
  {
     pEVDriver pNew = NULL;
     pSLSDriv pSim = NULL;
     
     /* check for arguments */
     if(argc < 2)
     {
       return NULL;
     }
     
     pNew = CreateEVDriver(argc,argv);
     pSim = (pSLSDriv)malloc(sizeof(SLSDriv));
     memset(pSim,0,sizeof(SLSDriv));
     if(!pNew || !pSim)
     {
       return NULL;
     }
     pNew->pPrivate = pSim;
     pNew->KillPrivate = KillSLS;

     pSim->controller = FindCommandData(pServ->pSics, argv[0],"RS232 Controller");
     if(pSim->controller == NULL){
    	 return NULL;
     }
     pSim->iNum = atoi(argv[1]);
     
     /* initialise function pointers */
     pNew->SetValue = SLSRun;
     pNew->GetValue = GetSLSPos;
     pNew->Send     = SLSSend;
     pNew->GetError = SLSError;
     pNew->TryFixIt = SLSFix;
     pNew->Init     = SLSInit;
     pNew->Close    = SLSClose;
     
     return pNew; 
  }	
  


