/*------------------------------------------------------------------------
                                  P S I

 This is the site specific interface to SICS for PSI. This file implements
 the interface defined in  ../site.h

 copyright: see file COPYRIGHT

 Mark Koennecke, June 2003 - May 2007
 -----------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <fortify.h>
#include <sics.h>
#include <motor.h>
#include <tcl.h>
#include <site.h>
#include "buffer.h"
#include "dmc.h"
#include "nxsans.h"
#include "nextrics.h"
#include "sps.h"
#include "pimotor.h"
#include "sanswave.h"
#include "faverage.h"
#include "fowrite.h"
#include "amor2t.h"
#include "nxamor.h"
#include "amorstat.h"
#include "tas.h"
#include "swmotor.h"
#include "polterwrite.h"
#include "ecb.h"
#include "frame.h"
#include "ecbdriv.h"
#include "ecbcounter.h"
#include <stringdict.h>
#include "sinqhmdriv.i"
#include "tdchm.h"
#include "tecsdriv.h"
#include "itc4.h"
#include "bruker.h"
#include "ltc11.h"
#include "A1931.h"
#include "dilludriv.h"
#include "eurodriv.h"
#include "el755driv.h"
#include <evdriver.i>
#include "amorscan.h"
#include "serial.h"
#include "fomerge.h"
#include "remob.h"
#include "tricssupport.h"
#include "sinq.h"
#include "tabledrive.h"
#include "amorset.h"
#include "sinqhttp.h"
#include "poldizug.h"
/* 
  from tcpdornier.c
*/
extern int VelSelTcpFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
                     int argc, char *argv[]);
/*
 * from julcho.c
 */
extern int JulChoFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
                     int argc, char *argv[]);
/* from ritastorage.c */                     
extern int MakeRitaFix(SConnection *pCon, SicsInterp *pSics, void *pData,
                     int argc, char *argv[]);
/* from sanslirebin.c */
extern int MakeSansliRebin(SConnection *pCon, SicsInterp *pSics, void *pData,
                     int argc, char *argv[]);
/* from lmd200.c */
extern int MakeLMD200(SConnection *pCon, SicsInterp *pSics, void *pData,
                     int argc, char *argv[]);
/* from julchoprot.c */
extern void AddJulChoProtocoll();
/* from sinqhttpprot.c */
extern void AddHttpProtocoll();

/*--------------------------------------------------------------------------*/
void SiteInit(void) {

#define INIT(F) { void F(void); F(); }

/* insert here initialization routines ... */

   INIT(IlmStartup);
   INIT(IpsStartup);
   INIT(ItcStartup);
   INIT(IghStartup);
   INIT(Euro2kStartup);
   INIT(StrObjStartup);
   INIT(ArrayObjStartup);
   INIT(Lsc370Startup);
   INIT(LinaStartup);
   INIT(HaakeStartup);
   INIT(AmiStartup);
   
   /*
    * SICS specific Asynchronous I/O protocols
    */
   AddJulChoProtocoll();
   AddHttpProtocoll();

}


static pSite sitePSI = NULL;

/*----------------------------------------------------------------------*/
static void AddPsiCommands(SicsInterp *pInter){
    AddCommand(pInter,"MakeRuenBuffer",InitBufferSys,NULL,NULL);
    AddCommand(pInter,"InitDMC",InitDmc,NULL,NULL);
    AddCommand(pInter,"InitSANS",InitSANS,NULL,NULL);
    AddCommand(pInter,"MakeTRICSNEXUS",NexTricsFactory,NULL,NULL);
    AddCommand(pInter,"MakeTRICSSupport",MakeTricsSupport,NULL,NULL);
    AddCommand(pInter,"MakeSPS",SPSFactory,NULL,NULL);
    AddCommand(pInter,"MakePIMotor",PIMotorFactory,NULL,NULL);
    AddCommand(pInter,"MakeSANSWave",MakeSANSWave,NULL,NULL);
    AddCommand(pInter,"MakeFocusAverager",MakeFA,NULL,NULL);
    AddCommand(pInter,"FocusInstall",FoInstall,NULL,NULL);
    AddCommand(pInter,"MakeAmor2T",Amor2TFactory,NULL,NULL);
    AddCommand(pInter,"MakeStoreAmor",AmorStoreMake,NULL,NULL);
    AddCommand(pInter,"MakeAmorStatus",AmorStatusFactory,NULL,NULL);
    AddCommand(pInter,"MakeTAS",TASFactory,NULL,NULL);
    AddCommand(pInter,"MakeSWMotor",MakeSWMotor,NULL,NULL);
    AddCommand(pInter,"MakeSWHPMotor",MakeSWHPMotor,NULL,NULL);
    AddCommand(pInter,"PolterInstall",PolterInstall,NULL,NULL);
    AddCommand(pInter,"MakeECB",MakeECB,NULL,NULL);
    AddCommand(pInter,"MakePSDFrame",MakeFrameFunc,NULL,NULL);
    AddCommand(pInter,"SerialInit",SerialInit,NULL,NULL);
    AddCommand(pInter,"InstallFocusMerge",InstallFocusMerge,NULL,NULL);
    AddCommand(pInter,"Remob",RemobCreate,NULL,NULL);
    AddCommand(pInter,"MakeSinq",SinqFactory,NULL,NULL);
    AddCommand(pInter,"MakeTableDrive",TableDriveFactory,NULL,NULL);
    AddCommand(pInter,"MakeAmorSet",AmorSetFactory,NULL,NULL);
    AddCommand(pInter,"MakeTCPSelector",VelSelTcpFactory,NULL,NULL);
    AddCommand(pInter,"MakeJulCho",JulChoFactory,NULL,NULL);
    AddCommand(pInter,"MakeRitaFix",MakeRitaFix,NULL,NULL);
    AddCommand(pInter,"MakePoldiReiss",MakePoldiReiss,NULL,NULL);
    AddCommand(pInter,"MakeSansliRebin",MakeSansliRebin,NULL,NULL);
    AddCommand(pInter,"MakeLMD200",MakeLMD200,NULL,NULL);
/*
    AddCommand(pInter,"MakeDifrac",MakeDifrac,NULL,NULL);
*/
}
/*---------------------------------------------------------------------*/
static void RemovePsiCommands(SicsInterp *pSics){
    RemoveCommand(pSics,"InitDMC");
    RemoveCommand(pSics,"InitSANS");
    RemoveCommand(pSics,"MakeTRICSNEXUS");
    RemoveCommand(pSics,"MakeTRICSSupport");
    RemoveCommand(pSics,"MakeSPS");
    RemoveCommand(pSics,"MakePIMotor");
    RemoveCommand(pSics,"MakeSANSWave");
    RemoveCommand(pSics,"MakeFocusAverager");
    RemoveCommand(pSics,"FocusInstall");
    RemoveCommand(pSics,"InstallFocusMerge");
    RemoveCommand(pSics,"MakeAmor2T");
    RemoveCommand(pSics,"MakeStoreAmor");
    RemoveCommand(pSics,"MakeAmorStatus");
    RemoveCommand(pSics,"MakeTCPSelector");
    RemoveCommand(pSics,"MakeJulCho");
    RemoveCommand(pSics,"MakeRitaFix");
    RemoveCommand(pSics,"MakePoldiReiss");
    RemoveCommand(pSics,"MakeSansliRebin");
    RemoveCommand(pSics,"MakeLMD200");
/*
    RemoveCommand(pSics,"MakeDifrac");
*/
    RemoveCommand(pSics,"MakeTAS");
    RemoveCommand(pSics,"MakeSWMotor");
    RemoveCommand(pSics,"PolterInstall");
    RemoveCommand(pSics,"MakeECB");
    RemoveCommand(pSics,"MakePSDFrame");
    RemoveCommand(pSics,"SerialInit");
    RemoveCommand(pSics,"MakeSinq");
    RemoveCommand(pSics,"MakeTableDrive");
    RemoveCommand(pSics,"MakeAmorSet");
}
/*---------------------------------------------------------------------*/
  MotorDriver *CreateEL734(SConnection *pCon, int argc, char *argv[]);
  MotorDriver *CreateEL734DC(SConnection *pCon, int argc, char *argv[]);
  MotorDriver *CreateEL734HP(SConnection *pCon, int argc, char *argv[]);
  MotorDriver *CreateEL734HPT(SConnection *pCon, int argc, char *argv[]);
  MotorDriver *MakePiPiezo(Tcl_Interp *pTcl,char *pArray);
/*-------------------------------------------------------------------*/
static pMotor CreatePsiMotor(SConnection *pCon, int argc, char *argv[]){
  MotorDriver *pDriver = NULL;
  pMotor pNew = NULL;
  Tcl_Interp *pTcl = NULL;
  char pBueffel[132];

  if(strcmp(argv[1],"pipiezo") == 0){
    pTcl = InterpGetTcl(pServ->pSics);
    pDriver = (MotorDriver *)MakePiPiezo(pTcl,argv[2]);
    if(!pDriver){
      SCWrite(pCon,pTcl->result,eError);
      return NULL;
    }
    /* create the motor */
    pNew  = MotorInit("PIPIEZO",argv[0],pDriver);
    if(!pNew){
      sprintf(pBueffel,"Failure to create motor %s",argv[0]);
      SCWrite(pCon,pBueffel,eError);
      return NULL; 
    }
  } else if(strcmp(argv[1],"el734") == 0){
    pDriver = (MotorDriver *)CreateEL734(pCon,argc-2,&argv[2]);
    if(!pDriver){
       return NULL;
    }
    /* create the motor */
    pNew  = MotorInit("EL734",argv[0],pDriver);
    if(!pNew){
      sprintf(pBueffel,"Failure to create motor %s",argv[1]);
      SCWrite(pCon,pBueffel,eError);
      return NULL; 
    }
  } else if(strcmp(argv[1],"el734hp") == 0){
    pDriver = (MotorDriver *)CreateEL734HP(pCon,argc-2,&argv[2]);
    if(!pDriver){
       return NULL;
    }
    /* create the motor */
    pNew  = MotorInit("EL734HP",argv[0],pDriver);
    if(!pNew){
      sprintf(pBueffel,"Failure to create motor %s",argv[1]);
      SCWrite(pCon,pBueffel,eError);
      return NULL; 
    }
  } else if(strcmp(argv[1],"el734hpt") == 0){
    pDriver = (MotorDriver *)CreateEL734HPT(pCon,argc-2,&argv[2]);
    if(!pDriver){
       return NULL;
    }
    /* create the motor */
    pNew  = MotorInit("EL734HPT",argv[0],pDriver);
    if(!pNew){
      sprintf(pBueffel,"Failure to create motor %s",argv[1]);
      SCWrite(pCon,pBueffel,eError);
      return NULL; 
    }
  } else if(strcmp(argv[1],"el734dc") == 0){
    pDriver = (MotorDriver *)CreateEL734DC(pCon,argc-2,&argv[2]);
    if(!pDriver){
       return NULL;
    }
    /* create the motor */
    pNew  = MotorInit("EL734DC",argv[0],pDriver);
    if(!pNew){
      sprintf(pBueffel,"Failure to create motor %s",argv[1]);
      SCWrite(pCon,pBueffel,eError);
      return NULL; 
    }
  } else if(strcmp(argv[1],"ecb") == 0){
    pDriver = (MotorDriver *)CreateECBMotor(pCon,argc-2,&argv[2]);
    if(!pDriver){
      return NULL;
    }
    /* create the motor */
    pNew  = MotorInit("ECB",argv[0],pDriver);
    if(!pNew){
      sprintf(pBueffel,"Failure to create motor %s",argv[0]);
      SCWrite(pCon,pBueffel,eError);
      return NULL; 
    }
  }
  return pNew;
}
/*-------------------------------------------------------------------*/
extern pCounterDriver CreateEL737Counter(SConnection *pCon, char *name,
					 int argc, char *argv[]);
extern pCounterDriver MakeEL737HP(SConnection *pCon, char *name, 
				  int argc, char *argv[]);
extern pCounterDriver MakeEL737HPV2(SConnection *pCon, char *name, 
				  int argc, char *argv[]);
pCounterDriver MakeEL737hpsps(SConnection *pCon, char *name, 
               int argc, char *argv[]);
/*-------------------------------------------------------------------*/
static pCounterDriver CreatePsiCounterDriver(SConnection *pCon,
					     int argc,
					     char *argv[]){
  pCounterDriver pNew = NULL;

  /*
    our caller has already checked for enough arguments
  */
  if(strcmp(argv[2],"el737") == 0){
    pNew = CreateEL737Counter(pCon,argv[1],argc-3,&argv[3]);
  } else if(strcmp(argv[2],"el737hp") == 0){
    pNew = MakeEL737HP(pCon,argv[1],argc-3,&argv[3]);
  } else if(strcmp(argv[2],"el737hpsps") == 0){
    pNew = MakeEL737hpsps(pCon,argv[1],argc-3,&argv[3]);
  } else if(strcmp(argv[2],"el737hpv2") == 0){
    pNew = MakeEL737HPV2(pCon,argv[1],argc-3,&argv[3]);
  } else if(strcmp(argv[2],"ecb") == 0){
    if(argc < 4){
      SCWrite(pCon,
	      "ERROR: insufficient no of arguments to create ECB counter",
	      eError);
      return NULL;
    }
    pNew = MakeECBCounter(argv[3]);
  }
  return pNew;
}
/*-------------------------------------------------------------------*/
extern pHistDriver MakeDelcamHM(pStringDict options); /* in delcam.c */
/*--------------------------------------------------------------------*/
static HistDriver *CreatePsiHistMem(char *name, pStringDict pOptions){
  HistDriver *pNew = NULL;
  
  if(strcmp(name,"sinqhm") == 0){
    pNew = CreateSINQDriver(pOptions);
  } else if(strcmp(name,"tdc") == 0){
    pNew = MakeTDCHM(pOptions);
  } else if(strcmp(name,"sinqhttp") == 0){
    pNew = CreateSinqHttpDriver(pOptions);
  } else if(strcmp(name,"delcam") == 0){
    pNew = MakeDelcamHM(pOptions);
  }
  return pNew;
}
/*-------------------------------------------------------------------*/
  extern pVelSelDriv VSCreateDornierSINQ(char *name,Tcl_Interp *pTcl);
  extern pVelSelDriv VSCreateDornier2003(char *name,Tcl_Interp *pTcl);
/*-------------------------------------------------------------------*/
static pVelSelDriv CreatePsiVelSelDriv(char *name, char *array, 
				       Tcl_Interp *pTcl){
  pVelSelDriv pNew = NULL;
  if(strcmp(name,"dornier") == 0){
    pNew = VSCreateDornierSINQ(array,pTcl);
  } else if(strcmp(name,"dornier2003") == 0){
    pNew = VSCreateDornier2003(array,pTcl);
  }
  return pNew;
}
/*------------------------------------------------------------------*/
extern pCodri MakeDoChoDriver(char *pHost, int iPort, int iChannel, 
                              int iSingle);
extern pCodri MakeCookerDriver(char *pHost, int iPort, int iChannel);
extern pCodri MakeTcpDoChoDriver(char *tclArray, SConnection *pCon);
/*-------------------------------------------------------------------*/
static pCodri CreatePsiController(SConnection *pCon,int argc, char *argv[]){
  pCodri pNew = NULL;
  Tcl_Interp *pTcl = InterpGetTcl(pServ->pSics);
  int iPort, iChannel, iRet, iSingle = 0;
  char pBueffel[512];

  if(strcmp(argv[0],"docho") == 0) {
     if(argc < 4) {
           SCWrite(pCon,
  "ERROR: Insufficient number of arguments to install Dornier Chopper driver",
           eError);
           return NULL;    
     }
     iRet = Tcl_GetInt(pTcl,argv[2],&iPort);
     if(iRet != TCL_OK){
       sprintf(pBueffel,"ERROR: expected integer as port number, got %s",
	       argv[2]);
       SCWrite(pCon,pBueffel,eError);
       return NULL;
     }
     iRet = Tcl_GetInt(pTcl,argv[3],&iChannel);
     if(iRet != TCL_OK){
       sprintf(pBueffel,"ERROR: expected integer as channel number, got %s",
                   argv[3]);
       SCWrite(pCon,pBueffel,eError);
       return NULL;
     }
     if(argc > 4) {
       iRet = Tcl_GetInt(pTcl,argv[4],&iSingle);
       if(iRet != TCL_OK){
	 sprintf(pBueffel,
		 "ERROR: expected integer as single flag, got %s",
		 argv[4]);
	 SCWrite(pCon,pBueffel,eError);
	 return NULL;
       }
     }
     pNew = MakeDoChoDriver(argv[1],iPort,iChannel,iSingle);
  } else if(strcmp(argv[0],"tcpdocho") == 0){
      if(argc < 2){
	  SCWrite(pCon,"ERROR: insufficient number of argumets for creating TcpDoCho",
		  eError);
	  return NULL;
      }
      return MakeTcpDoChoDriver(argv[1], pCon);
  }else if(strcmp(argv[0],"sanscook") == 0) {
    if(argc < 4){
      SCWrite(pCon,
  "ERROR: Insufficient number of arguments to install SANS Cooker driver",
           eError);
      return NULL;    
    }
    iRet = Tcl_GetInt(pTcl,argv[2],&iPort);
    if(iRet != TCL_OK){
      sprintf(pBueffel,"ERROR: expected integer as port number, got %s",
	      argv[2]);
      SCWrite(pCon,pBueffel,eError);
      return NULL;
    }
    iRet = Tcl_GetInt(pTcl,argv[3],&iChannel);
    if(iRet != TCL_OK){
      sprintf(pBueffel,"ERROR: expected integer as channel number, got %s",
	      argv[3]);
      SCWrite(pCon,pBueffel,eError);
      return NULL;
    }
    pNew = MakeCookerDriver(argv[1],iPort,iChannel);
  }
  return pNew;
}
/*-----------------------------------------------------------------
 ConfigureController is a helper function which configures parameters
 for certain controller types
 --------------------------------------------------------------------*/
static void ConfigureController(char *name, pEVControl pNew, 
				SConnection *pCon){
  EVCSetPar(pNew,"upperlimit",300.0,pCon);
  EVCSetPar(pNew,"lowerlimit",1.0,pCon);
  if(strcmp(name,"tecs") == 0){
    TecsCustomize(pCon, pNew);
  } else if(strcmp(name,"euro") == 0){
    EVCSetPar(pNew,"upperlimit",750.0,pCon);
    EVCSetPar(pNew,"lowerlimit",15.0,pCon);
  } else if(strcmp(name,"el755") == 0){
    EVCSetPar(pNew,"upperlimit",10.,pCon);
    EVCSetPar(pNew,"lowerlimit",-10.,pCon);
  } else if(strcmp(name,"bruker") == 0){
    EVCSetPar(pNew,"upperlimit",45.,pCon);
    EVCSetPar(pNew,"lowerlimit",0.,pCon);
  } else if(strcmp(name,"ltc11") == 0){
    EVCSetPar(pNew,"upperlimit",500.,pCon);
    EVCSetPar(pNew,"lowerlimit",1.5,pCon);
  }
}
/*-------------------------------------------------------------------*/
extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
extern pEVDriver CreateSLSVMEDriv(int argc, char *argv[]);
/*------------------------------------------------------------------*/

static pEVControl InstallPsiEnvironmentController(SicsInterp *pSics,
						  SConnection *pCon,
						 int argc, char *argv[]){
  pEVControl pNew = NULL;
  pEVDriver pDriv = NULL;
  int status = 1, checkError = 0, commandInstalled = 0;
  char pBueffel[512], pError[132]; 

  /*
    flag usage:
    checkError becomes 1 when a driver has been recognized and an error
    must be issued if something failed.
     commandInstalled becomes 1 when the command has already been installed 
     for the device. If 0 the default command will be installed later on
  */ 

  if(strcmp(argv[3],"tecs") == 0){ 
    checkError = 1;
    pDriv = CreateTecsDriver(argc-4,&argv[4]);
    if(pDriv != NULL){
      pNew = CreateEVController(pDriv,argv[2],&status);
      if(pNew){
	AddCommand(pSics,argv[2],TecsWrapper,DeleteEVController,pNew);
	commandInstalled = 1;
      }
    }
  } else if(strcmp(argv[3],"itc4") == 0) {
    checkError = 1;
    pDriv = CreateITC4Driver(argc-4,&argv[4]);
    if(pDriv){
      pNew = CreateEVController(pDriv,argv[2],&status);
      if(pNew != NULL){
	AddCommand(pSics,argv[2],ITC4Wrapper,DeleteEVController,
		   pNew);
	commandInstalled = 1;
      }
    }
  } else if(strcmp(argv[3],"bruker") == 0){
    checkError = 1;
    pDriv = CreateBrukerDriver(argc-4,&argv[4]);
    if(pDriv != NULL){
      pNew = CreateEVController(pDriv,argv[2],&status);
      if(pNew != NULL){
	AddCommand(pSics,argv[2],BrukerAction,DeleteEVController,
		   pNew);
	commandInstalled = 1;
      }
    }
  } else if(strcmp(argv[2],"ltc11") == 0){
    checkError = 1;
    pDriv = CreateLTC11Driver(argc-4,&argv[4]);
    if(pDriv != NULL){
      pNew = CreateEVController(pDriv,argv[2],&status);
      if(pNew != NULL){
	AddCommand(pSics,argv[2],LTC11Action,DeleteEVController,pNew);
	commandInstalled = 1;
      }
    }
  } else if(strcmp(argv[3],"a1931") == 0){
    checkError = 1;
    pDriv = CreateA1931Driver(argc-4,&argv[4]);
    if(pDriv != NULL){
      pNew = CreateEVController(pDriv,argv[2],&status);
      if(pNew != NULL){
	AddCommand(pSics,argv[2],A1931Action,DeleteEVController, pNew);
	commandInstalled = 1;
      }
    }
  } else if(strcmp(argv[3],"dillu") == 0){
    checkError = 1;
    pDriv = CreateDILLUDriv(argc-4,&argv[4]);
    if(pDriv != NULL){
      pNew = CreateEVController(pDriv,argv[2],&status);
    }
  } else if(strcmp(argv[3],"euro") == 0){
    checkError = 1;
    pDriv = CreateEURODriv(argc-4,&argv[4]);
    if(pDriv != NULL){
      pNew = CreateEVController(pDriv,argv[2],&status);
    }
  } else if(strcmp(argv[3],"psi-dsp") == 0) {
    checkError = 1;
    pDriv = CreateSLSDriv(argc-4,&argv[4]);
    if(pDriv != NULL){
      pNew = CreateEVController(pDriv,argv[2],&status);
    }
  } else if(strcmp(argv[3],"vme-dsp") == 0) {
    checkError = 1;
    pDriv = CreateSLSVMEDriv(argc-4,&argv[4]);
    if(pDriv != NULL){
      pNew = CreateEVController(pDriv,argv[2],&status);
    }
  } else if(strcmp(argv[3],"el755") == 0){
    checkError = 1;
    pDriv = CreateEL755Driv(argc-4,&argv[4]);
    if(pDriv != NULL){
      pNew = CreateEVController(pDriv,argv[2],&status);
    } 
  } else {
    sprintf(pBueffel,"ERROR: %s not recognized as a valid driver type", argv[3]);
    SCWrite(pCon,pBueffel,eError);
    return NULL;
  }

  /* if we recognized the driver, check for installation errors */
  if(checkError == 1){
    if(pDriv == NULL){
      SCWrite(pCon,"ERROR: failed to create driver",eError);
      return NULL;
    }
    if(status != 1) {
      SCWrite(pCon,"ERROR: failed to initialize device",
	      eError);
      pDriv->GetError(pDriv,&status,pError,131);
      sprintf(pBueffel,"HW reported: %s",pError);
      SCWrite(pCon,pBueffel,eError);
    }
    if(pNew == NULL){
      SCWrite(pCon,"ERROR: failed to create environment device object",
	      eError);
      DeleteEVDriver(pDriv);
      return NULL;
    }
    if(commandInstalled == 0){
      AddCommand(pSics,argv[2],EVControlWrapper,DeleteEVController,pNew);
    }
    ConfigureController(argv[3],pNew,pCon);
  }

  return pNew;
}
/*-----------------------------------------------------------------*/
static int ConfigurePsiScan(pScanData self, char *option){
  if(strcmp(option,"amor") == 0){
    ConfigureAmor(self);
    return 1;
  }
  return 0;
}
/*--------------------------------------------------------------------*/
static void KillPsi(void *site){
  free(site);
  sitePSI = NULL;
}
/*---------------------------------------------------------------------
  The scheme here goes along the lines of the singleton design pattern
  ---------------------------------------------------------------------*/
pSite getSite(void){
  if(sitePSI == NULL){
    sitePSI = (pSite)malloc(sizeof(Site));
    /*
      we  cannot go on if we do not even have enough memory to allocate
      the site data structure
    */
    assert(sitePSI); 
    /*
      initializing function pointers
    */
    sitePSI->AddSiteCommands = AddPsiCommands;
    sitePSI->RemoveSiteCommands = RemovePsiCommands;
    sitePSI->CreateMotor = CreatePsiMotor;
    sitePSI->CreateCounterDriver = CreatePsiCounterDriver;
    sitePSI->CreateHistogramMemoryDriver = CreatePsiHistMem; 
    sitePSI->CreateVelocitySelector = CreatePsiVelSelDriv;
    sitePSI->CreateControllerDriver = CreatePsiController;
    sitePSI->InstallEnvironmentController = InstallPsiEnvironmentController;
    sitePSI->ConfigureScan = ConfigurePsiScan;
    sitePSI->KillSite = KillPsi;
  }
  return sitePSI;
}

