 /*--------------------------------------------------------------------------
                     S L S M A G N E T

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

 This device runs a binary protocoll on its RS232 interface. And the lowest
 speed this device understands is 115KB! This is why this driver accesses 
 the terminal server port directly through the network without David's
 SerPortServer program in between. Also make sure that the port runs at
 115KB when using this device. 

 Mark Koennecke, October 2001 
 
 Adaptiert auf neue DSP Software version, Mark Koennecke, August 2005

 Fixed some bugs and added resetting of error conditions:
 Mark Koennecke, May 2007
 
 There is another scheme for resetting controller erros which might need
 to be implemented:
 1) switch the controller off
 2) Write 0 to 0x21
 3) switch on 
 4) drive to target
 This reboots the controller. Lukas Tanner does not recommend to do this 
 automatically. This is why it is not implemented yet. This reboot anyway 
 is not as hard as a full power cycle.   

 Copyright: see copyright.h
----------------------------------------------------------------------------*/
#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 "evdriver.h"
#include <network.h>
#include <rs232controller.h>

/*
  error codes
*/
#define BADECHO -5100
/* 
#define NOTCONNECTED -5200 
#define TIMEOUT      -5300
*/

/*
  when waiting for results, the code loops at max MAXLOOP times 
  before doing a timeout. 100 corresponds to one second
*/
#define MAXLOOP 100
#define BADLOWLIM -5301
#define BADHIGHLIM -5302
#define DEVICERROR -5304
/*
  packet header codes
*/
#define DSPWRITE 0x80
#define DSPREAD 0x0

#define ABS(x) (x < 0 ? -(x) : (x)) 

/*-----------------------------------------------------------------------*/
  typedef struct {
                   mkChannel *pSock;
                   char *pHost;
                   int iPort;
                   int iError;
                  } SLSDriv, *pSLSDriv;
/*-------------------------------------------------------------------------
 Code for data conversion from Lukas Tanner. The ULONG is system dependent,
 it MUST describe a 32 bit value.  
 -------------------------------------------------------------------------*/
#define ULONG int
/***********************************************************************/
static ULONG double2DSPfloat( double input )
/***********************************************************************/
/* Konvertiert eine normale double Variable in ein 32bit DSP Float Format. */
{
	ULONG output;
	double mantissa;
	int exponent;

	if (input == 0) {
		output = 0;
	} else {
		mantissa = 2 * (frexp(fabs(input), &exponent));
		mantissa = ldexp(mantissa, 23);
		exponent =exponent - 1 + 127;
		if (exponent < 0) {
			exponent = 0;
		} else if (exponent > 0xFE) {
			exponent = 0xFE;
		}
		exponent = exponent << 23;
		output = ((ULONG) mantissa) & 0x7FFFFF;
		output = output | ((ULONG) (exponent));
		if (input < 0) {
			output = output | 0x80000000;
		}
	}
    return output;
}

/***********************************************************************/
static double DSPfloat2double( ULONG input )
/***********************************************************************/
/* Konvertiert eine Variable inder ein 32bit DSP Float Wert abgelegt ist,
   in ein normales double Format
   32bit IEEE Float => SEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM;	S = Sign Bit
															E = Exponent
												   			M = Mantissa (23)*/
{
	double output;
	if ((input & 0x7FFFFF) == 0 && ((input >> 23) & 0xFF) == 0) {
		output = 0;
	} else {
		output = ldexp(input & 0x7FFFFF,-23) + 1;
		output = output * pow(-1, ((input >>31) & 1));
		output = output * ldexp(1, (((input >>23) & 0xFF) - 127));
	}
    return output;
}
/*-------------------------------------------------------------------------*/
static int communicateSLS(mkChannel *pSock, char msg[6], char reply[6])
{
  long lVal = 0;
  int iRet, i, address, status;

  if(!pSock)
    return NOTCONNECTED;

  memset(reply,0,6);
  address = (int)msg[1];
  iRet = NETWrite(pSock,msg,6);
  if(iRet < 0)
  {
    return iRet;
  }
  for(i = 0; i < MAXLOOP; i++)
  {
    iRet = NETAvailable(pSock,10);
    if(iRet < 0)
    {
      return iRet;
    }
    else if(iRet == 1)
    {
      status =  NETRead(pSock,reply+lVal,6-lVal,-10);
      if(status >= 0){
        lVal += status;
      } else {
        /*
         * network read error
         */
        return status;
      }
      if(lVal >= 6)
      {
        return (int)lVal;      
      }
      else
      {
	continue;
      }
    }
  }
  if((int)reply[1] != address){
    return BADECHO;
  }
  return TIMEOUT;
}
/*---------------------------------------------------------------------------*/
  static int GetSLSPos(pEVDriver  self, float *fPos)
  {
     pSLSDriv pMe = NULL;
     int iRet, ival, err;
     double dval;
     char msg[6], reply[6];
     long lVal;

     assert(self);
     pMe = (pSLSDriv)self->pPrivate;
     assert(pMe);
     
     memset(msg,0,6*sizeof(char));
     memset(reply,0,6*sizeof(char));
     msg[0] = DSPREAD; /* read request */
     /* old address of mag current 
     msg[1] = 0x92; 
     */
     msg[1] = 0x9c; /* address of mag current */
     iRet = communicateSLS(pMe->pSock,msg,reply);
     if(iRet < 0)
     {
       pMe->iError = iRet;
       return 0;
     }
     memcpy(&ival,reply+2,4);
     dval = DSPfloat2double(ival);
     *fPos = (float)dval;
     pMe->iError = 0;

     /*
      * try read error codes
      */
     msg[1] = 0x29;
     iRet = communicateSLS(pMe->pSock,msg,reply);
     if(iRet < 0)
     {
       pMe->iError = iRet;
       return 0;
     }
     err = (int)reply[5];
     if(err != 0){
     	pMe->iError = -7000 - err;
     	return 0;
     }
      
     return 1;
  } 
/*----------------------------------------------------------------------------*/
  static int SLSRun(pEVDriver self, float fVal)
  {
     pSLSDriv pMe = NULL;
     int iRet, ival, i;
     char msg[6], reply[6];
     double min, max;
     
     assert(self);
     pMe = (pSLSDriv )self->pPrivate;
     assert(pMe);

     memset(msg,0,6*sizeof(char));
     memset(reply,0,6*sizeof(char));

	 /*
	  * test high limit
	  */
     msg[0] = DSPREAD;
     msg[1] = 0x76;
     iRet = communicateSLS(pMe->pSock,msg,reply);
     if(iRet <= 0)
     {
       pMe->iError = iRet;
       return iRet;
     }
     memcpy(&ival,reply+2,4);
     max = DSPfloat2double(ival);
	 if(fVal > max){
	 	pMe->iError = BADHIGHLIM;
	 	return 0;
	 }

	 /*
	  * test low limit
	  */
     msg[0] = DSPREAD;
     msg[1] = 0x77;
     iRet = communicateSLS(pMe->pSock,msg,reply);
     if(iRet <= 0)
     {
       pMe->iError = iRet;
       return iRet;
     }
     memcpy(&ival,reply+2,4);
     min = -ABS(DSPfloat2double(ival));
	 if(fVal < min){
	 	pMe->iError = BADLOWLIM;
	 	return 0;
	 }
	 
	 /*
	  * actual set the new value
	  */
     msg[0] = DSPWRITE;
     msg[1] = 0x90;
     ival = double2DSPfloat((double)fVal);
     memcpy(msg+2, &ival,4);
     iRet = communicateSLS(pMe->pSock,msg,reply);
     if(iRet <= 0)
     {
       pMe->iError = iRet;
       return 0;
     }
     for(i = 1; i < 6; i++)
     {
       if(msg[i] != reply[i])
       {
	 pMe->iError = BADECHO;
         return 0;
       }
     }
     return 1;
 }
 /*---------------------------------------------------------------------*/
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 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(*iCode < -7000){
     	slsdspCodeToText(-(pMe->iError + 7000),error,iErrLen);
     	return 1;
     }
     	 	
     
     switch(*iCode)
     {
     case BADECHO:
       strncpy(error,"message sent and reply did not match", iErrLen);
       break;
     case NOTCONNECTED:
       strncpy(error,"Not connected to device", iErrLen);
       break;
     case TIMEOUT:
       strncpy(error,"Timeout waiting for response", iErrLen);
       break;
     case BADHIGHLIM:
     	strncpy(error,"Device internal upper limit violated",iErrLen);
     	break;
     case BADLOWLIM:
     	strncpy(error,"Device internal lower limit violated",iErrLen);
     	break;
     default:
       getRS232Error(*iCode,error,iErrLen);
       break;
     }  
    
    return 1;
  }
/*-------------------------------------------------------------------------*/
  static int SLSSend(pEVDriver self, char *pCommand, char *pReply, int iLen)
  {
      pSLSDriv pMe = NULL;
     int iRet, ival;
     char msg[6], reply[6];
 
     assert(self);
     pMe = (pSLSDriv )self->pPrivate;
     assert(pMe);

 
 
     msg[0] = DSPWRITE;
     msg[1] = 0x3c;
     if(strcmp(pCommand,"off") == 0){
         /*
        * ival = 0: ausschalten
        */
        ival = 0;
        memcpy(msg+2, &ival,4);
        iRet = communicateSLS(pMe->pSock,msg,reply);
        if(iRet <= 0)
        {
            pMe->iError = iRet;
            SLSError(self,&ival,pReply,iLen);
            return 0;
        } else {
            strncpy(pReply,"Done",iLen);
            return 1;
        }
     } else if(strcmp(pCommand,"on") == 0){
         /*
        * ival = 1: einschalten
        */
        ival = 1;
        memcpy(msg+2, &ival,4);
        iRet = communicateSLS(pMe->pSock,msg,reply);
        if(iRet <= 0)
        {
            pMe->iError = iRet;
            SLSError(self,&ival,pReply,iLen);
            return 0;
        } else {
            strncpy(pReply,"Done",iLen);
            return 1;
        }
     } else  {
        strncpy(pReply,"SLSMagnet only understands on or off on send",
            iLen);
        return 0;
     }
    

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

     pMe->pSock = NULL;
     pMe->pSock = NETConnect(pMe->pHost,pMe->iPort);
     if(!pMe->pSock)
     {
       return 0;
     }

     sleep(1); 

     /*
       try to switch device on
     */
     msg[0] = DSPWRITE;
     msg[1] = 0x3c;
     /*
      * ival = 0: ausschalten
      */
     ival = 1;
     memcpy(msg+2, &ival,4);
     iRet = communicateSLS(pMe->pSock,msg,reply);
     if(iRet <= 0)
     {
       pMe->iError = iRet;
       return iRet;
     }
     for(i = 1; i < 6; i++)
     {
       if(msg[i] != reply[i])
       {
    	 pMe->iError = BADECHO;
         return BADECHO;
       }
     }

     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);

    /*
     msg[0] = DSPWRITE;
     msg[1] = 0x3c;
     ival = 0;
     memcpy(msg+2, &ival,4);
     iRet = communicateSLS(pMe->pSock,msg,reply);
    */
     NETClosePort(pMe->pSock);
     pMe->pSock = NULL;
     return 1;
  }  
/*---------------------------------------------------------------------------*/
  static int SLSFix(pEVDriver self, int iError)
  {
     pSLSDriv pMe = NULL;
     int iRet, i, ival;
     char buffer[80];
     char msg[6], reply[6];
     float fVal = .0;
     
     assert(self);
     pMe = (pSLSDriv )self->pPrivate;
     assert(pMe);

	 if(iError < -7000){
        /* 
         * This logic tries to reset the error code. Then it reads the 
         * error back. Serious errors persist and must be fixed by magnet 
         * technicians. But some can be cleared.... 
         */
        msg[0] = DSPWRITE;
        msg[1] = 0x29;
        ival = double2DSPfloat((double)fVal);
        memcpy(msg+2, &ival,4);
        communicateSLS(pMe->pSock,msg,reply);
        /*
         * read again: if persists: this is really, really bad
         */
        msg[0] = DSPREAD;
        msg[1] = 0x29;
        iRet = communicateSLS(pMe->pSock,msg,reply);
        if(iRet < 0)
        {
            return DEVFAULT;
        }
        ival  = (int)reply[5];
        if(ival == 0){
            return DEVREDO;
        } 
        /*
         * OK, clearing the error did not work, I try to reinitialize the 
         * socket because this helps sometimes.
         */
         NETClosePort(pMe->pSock);
         pMe->pSock = NULL;
         pMe->pSock = NETConnect(pMe->pHost,pMe->iPort);
         if(!pMe->pSock)
         {
           return DEVFAULT;
         }
         sleep(1); 
         msg[0] = DSPREAD;
         msg[1] = 0x29;
         iRet = communicateSLS(pMe->pSock,msg,reply);
         if(iRet < 0)
         {
            return DEVFAULT;
         }
         ival  = (int)reply[5];
         if(ival == 0){
            return DEVREDO;
         } else {
            return DEVFAULT;
         } 
	 }
	 
     switch(iError)
     {
     		case BADHIGHLIM:
     		case BADLOWLIM:
     		      return DEVFAULT;
     		      break;
            case BADECHO:
            case TIMEOUT:
                for(i = 0; i < 10; i++){
                    iRet = NETAvailable(pMe->pSock,0);
                    if(iRet == 1){
                        NETRead(pMe->pSock, buffer,70,-10);
                    }
                }
                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;
  }
/*------------------------------------------------------------------------*/
  void KillSLS(void *pData)
  {
     pSLSDriv pMe = NULL;
     
     pMe = (pSLSDriv)pData;
     assert(pMe);
     
     if(pMe->pHost)
     {
        free(pMe->pHost);
     }
     free(pMe);
  }  
/*------------------------------------------------------------------------*/
  pEVDriver CreateSLSDriv(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->pHost = strdup(argv[0]);
     pSim->iPort = 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; 
  }	
  


