/*------------------------------------------------------------------------ File: anstoSite.c This is the site specific interface to SICS for ANSTO. This file implements the interface defined in ../site.h Copyright: see file Copyright.txt Template: Mark Koennecke, June 2003 Nick Hauser, Paul Hathaway, May 2004 $Name: not supported by cvs2svn $ $Revision: 1.23.2.5 $ -----------------------------------------------------------------------*/ #include "made_config.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SICS_VALGRIND #include #endif #include "protocol.h" #include "sicslist.h" #include "macro.h" #include "status.h" /* site-specific driver header files */ #include "motor_dmc2280.h" #include "motor_asim.h" #include "itc4.h" /* Added code for new LH45 and Lakeshore 340 drivers */ #include "lh45.h" #include "lakeshore340.h" #include "west4100.h" /* Added HTTP support for ANSTO OPAL NBI Histogram Server */ #include "anstohttp.h" #include "anstoutil.h" /* Added customized HMControl object to support ANSTO OPAL NBI Histogram Server */ #include "hmcontrol.h" #include "hmcontrol_ansto.h" // extends hmcontrol.h /* Added code for NHQ200 HV Power Supply */ #include "nhq200.h" /* Added code for Oak Ridge High Voltage Power Supply */ #include "orhvps.h" /* Added code for new LS340 LAKESORE 340 Temperature Controller */ #include "ls340.h" #include "safetyplc.h" #include "lssmonitor.h" #include "beamstopaction.h" #include "cameradriver.h" #include "aqp_opalstatus.h" #include "omron_asyncprotocol.h" #include "huber_asyncprotocol.h" /*@observer@*//*@null@*/ pCounterDriver CreateMonCounter(/*@observer@*/SConnection *pCon, /*@observer@*/char *name, char *params); extern void AddGalilProtocoll(); extern void AddModbusProtocoll(); extern void AddOxfordProtocoll(); extern void AddNewportProtocoll(); extern void AddOrdHVPSProtocoll(); extern void AddVelSelProtocol(); extern void AddUSBTMCProtocoll(); extern void AddHttpProtocoll(); extern void AddProtek608Protocol(); extern void AddRFAmpProtocol(); extern void AddTCPMBProtocol (); extern void AddLFGenProtocol(); extern void AddSCAQAProtocol(); extern int ANSTO_MakeHistMemory(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); extern int testLogCmd(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); extern pCounterDriver CreateCam(SConnection *pCon, char *name, char *asynq); int SICS_Site(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { char line[132]; #ifdef SICS_SITE snprintf(line, 132, "SICS_Site = %s", SICS_SITE); #else snprintf(line, 132, "SICS_Site = ANSTO"); #endif SCWrite(pCon, line, eValue); return OKOK; }; int SICS_Version(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { char line[132]; #ifdef SICS_VERSION snprintf(line, 132, "SICS_Version = %s", SICS_VERSION); #else snprintf(line, 132, "SICS_Version = UNKNOWN"); #endif SCWrite(pCon, line, eValue); return OKOK; }; int SICS_Revision(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { char line[132]; #ifdef SICS_REVISION snprintf(line, 132, "SICS_Revision = %s", SICS_REVISION); #else snprintf(line, 132, "SICS_Revision = UNKNOWN"); #endif SCWrite(pCon, line, eValue); return OKOK; }; static int Ansto_Valgrind(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { /* check authorisation: only users permitted here */ if (!SCMatchRights(pCon, usUser)) { SCWrite(pCon, "ERROR: Insufficient Privilege to do Valgrind", eError); return 0; } /* check enough arguments */ if (argc < 2) { SCWrite(pCon, "ERROR: Valgrind subcommand not specified ", eError); return 0; } if (strcasecmp(argv[1], "added") == 0) { #ifdef VALGRIND_DO_ADDED_LEAK_CHECK VALGRIND_DO_ADDED_LEAK_CHECK; SCSendOK(pCon); #else SCPrintf(pCon, eError, "VALGRIND_DO_ADDED_LEAK_CHECK not supported for %s", argv[1]); #endif return OKOK; } if (strcasecmp(argv[1], "changed") == 0) { #ifdef VALGRIND_DO_CHANGED_LEAK_CHECK VALGRIND_DO_CHANGED_LEAK_CHECK; SCSendOK(pCon); #else SCPrintf(pCon, eError, "VALGRIND_DO_CHANGED_LEAK_CHECK not supported for %s", argv[1]); #endif return OKOK; } if (strcasecmp(argv[1], "quick") == 0) { #ifdef VALGRIND_DO_QUICK_LEAK_CHECK VALGRIND_DO_QUICK_LEAK_CHECK; SCSendOK(pCon); #else SCPrintf(pCon, eError, "VALGRIND_DO_QUICK_LEAK_CHECK not supported for %s", argv[1]); #endif return OKOK; } if (strcasecmp(argv[1], "check") == 0) { #ifdef VALGRIND_DO_LEAK_CHECK VALGRIND_DO_LEAK_CHECK; SCSendOK(pCon); #else SCPrintf(pCon, eError, "VALGRIND_DO_LEAK_CHECK not supported for %s", argv[1]); #endif return OKOK; } if (strcasecmp(argv[1], "bytes") == 0) { #ifdef VALGRIND_COUNT_LEAKS static long int leaked_bytes = 0; static long int dubious_bytes = 0; static long int reachable_bytes = 0; static long int suppressed_bytes = 0; long int leaked = 0; long int dubious = 0; long int reachable = 0; long int suppressed = 0; VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed); if (argc > 2 && strcasecmp(argv[2], "delta") == 0) { SCPrintf(pCon, eLog, "Valgrind delta bytes: leaked=%ld, dubious=%ld, reachable=%ld, suppressed=%ld", leaked - leaked_bytes, dubious - dubious_bytes, reachable - reachable_bytes, suppressed - suppressed_bytes); } else { SCPrintf(pCon, eLog, "Valgrind bytes: leaked=%ld, dubious=%ld, reachable=%ld, suppressed=%ld", leaked, dubious, reachable, suppressed); } leaked_bytes = leaked; dubious_bytes = dubious; reachable_bytes = reachable; suppressed_bytes = suppressed; #else SCPrintf(pCon, eError, "VALGRIND_COUNT_LEAKS not supported for %s", argv[1]); #endif return OKOK; } if (strcasecmp(argv[1], "blocks") == 0) { #ifdef VALGRIND_COUNT_LEAK_BLOCKS static long int leaked_blocks = 0; static long int dubious_blocks = 0; static long int reachable_blocks = 0; static long int suppressed_blocks = 0; long int leaked = 0; long int dubious = 0; long int reachable = 0; long int suppressed = 0; VALGRIND_COUNT_LEAK_BLOCKS(leaked, dubious, reachable, suppressed); if (argc > 2 && strcasecmp(argv[2], "delta") == 0) { SCPrintf(pCon, eLog, "Valgrind delta blocks: leaked=%ld, dubious=%ld, reachable=%ld, suppressed=%ld", leaked - leaked_blocks, dubious - dubious_blocks, reachable - reachable_blocks, suppressed - suppressed_blocks); } else { SCPrintf(pCon, eLog, "Valgrind blocks: leaked=%ld, dubious=%ld, reachable=%ld, suppressed=%ld", leaked, dubious, reachable, suppressed); } leaked_blocks = leaked; dubious_blocks = dubious; reachable_blocks = reachable; suppressed_blocks = suppressed; #else SCPrintf(pCon, eError, "VALGRIND_COUNT_LEAK_BLOCKS not supported for %s", argv[1]); #endif return OKOK; } SCPrintf(pCon, eError, "Valgrind subcommand not supported for %s", argv[1]); return OKOK; } void SiteReportVersion(void) { fprintf(stdout, "SICS version=%s revision=%s at %s\n", SICS_VERSION, SICS_REVISION, SICS_SITE); } static int MacroFileEvalGlob(SConnection * pCon, SicsInterp * pInter, void *pData, int argc, char *argv[]) { int i; int rv; int flags; Status eOld; glob_t globbuf; char *args[3]; assert(pCon); assert(pInter); /* check authorisation: only users permitted here */ if (!SCMatchRights(pCon, usUser)) { SCWrite(pCon, "ERROR: Insufficient Privilege to do FileEval", eError); return 0; } /* check enough arguments */ if (argc < 2) { SCWrite(pCon, "ERROR: No filename specified ", eError); return 0; } /* handle status first */ eOld = GetStatus(); SetStatus(eBatch); flags = GLOB_NOSORT; #if defined(GLOB_BRACE) flags |= GLOB_BRACE; #endif #if defined(GLOB_TILDE_CHECK) flags |= GLOB_TILDE_CHECK; #endif memset(&globbuf, 0, sizeof(globbuf)); for (i = 1; i < argc; ++i) { glob(argv[i], flags, NULL, &globbuf); flags |= GLOB_APPEND; } args[0] = "fileeval"; args[2] = NULL; rv = 1; for (i = 0; i < (int) globbuf.gl_pathc; ++i) { args[1] = globbuf.gl_pathv[i]; SCPrintf(pCon, eLog, "fileeval %s", args[1]); if (0 == MacroFileEval(pCon, pInter, pData, 2, args)) rv = 0; } if (0 == globbuf.gl_pathc) { SCWrite(pCon, "ERROR: No file(s) found in FileEvalGlob", eError); rv = 0; } globfree(&globbuf); SetStatus(eOld); if (1 == rv) SCSendOK(pCon); return rv; } /* Test of the logging facilities */ int testLogCmd(SConnection *pCon, SicsInterp *pInter, void *pData, int argc, char *argv[]) { char lbuf[2048]; char sbuf[1000]; int i; SICSLogWrite("Multiline:\nLine 1\r\nLine 2\r\nLine 3\r\n", eLog); memset(lbuf, 0, sizeof(lbuf)); memset(sbuf, ' ', sizeof(sbuf)); SICSLogPrintf(eLog, "Hexlog %d all zero bytes", sizeof(lbuf)); SICSLogWriteHex(lbuf, sizeof(lbuf), eLog); for (i = 0; i <= 128; ++i) sbuf[i] = sbuf[sizeof(sbuf) - 1 - i] = i; sbuf[sizeof(sbuf) / 2] = '!'; SICSLogPrintf(eLog, "Hexlog %d mid space bytes", sizeof(sbuf)); SICSLogWriteHex(sbuf, sizeof(sbuf), eLog); for (i = 0; i < 1000; ++i) sbuf[i] = ' ' + (i % 96); sbuf[sizeof(sbuf) - 1] = '\0'; SICSLogWrite("Very long line 1000 bytes", eLog); SICSLogWrite(sbuf, eLog); SCSendOK(pCon); return OKOK; } /** * \brief Writes multiline output from a command to a client. * This is useful for implementing Tcl proc wrappers for commands. * NOTE: SICS-764, currently this sends output to the client as well as capturing it. * We should try to improve this in Release 3.2 see SICS-765 */ int Ansto_Capture(SConnection *pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { char buffer[1024]; char *command, *data; int status, inMacro; if (argc < 2) { SCWrite(pCon, "ERROR: insufficient arguments to capture", eError); return 0; } command = Arg2Tcl(argc - 1, &argv[1], buffer, sizeof buffer); inMacro = pCon->iMacro; pCon->iMacro = 0; status = InterpExecute(pSics, pCon, command); pCon->iMacro = inMacro; if (command != buffer) free(command); data = ANETgetWBuffer(pCon->sockHandle); SCWrite(pCon, data, eValue); return status; } void SiteInit(void) { #define INIT(F) { void F(void); F(); } /* insert here initialization routines ... */ INIT(SctEmonInit); INIT(ANSTO_SctDriveInit); AddGalilProtocoll(); AddModbusProtocoll(); AddOxfordProtocoll(); AddNewportProtocoll(); AddOrdHVPSProtocoll(); AddVelSelProtocol(); AddUSBTMCProtocoll(); AddHttpProtocoll(); AddProtek608Protocol(); AddRFAmpProtocol(); AddTCPMBProtocol(); AddLFGenProtocol(); AddSCAQAProtocol(); } static pSite /*@null@*/ siteANSTO = NULL; /*----------------------------------------------------------------------*/ static void AddCommands(SicsInterp *pInter) { DMC2280InitProtocol(pInter); SafetyPLCInitProtocol(pInter); LSSInitProtocol(pInter); NHQ200InitProtocol(pInter); ORHVPSInitProtocol(pInter); LS340InitProtocol(pInter); CameraInitProtocol(pInter); OpalStatusInitProtocol(pInter); LOADERInitProtocol(pInter); AddCommand(pInter,"InstallProtocolHandler", InstallProtocol,NULL,NULL); AddCommand(pInter,"hostnam",hostNamCmd,NULL,NULL); AddCommand(pInter,"portnum",portNumCmd,NULL,NULL); AddCommand(pInter,"abortbatch",AbortBatch,NULL,NULL); AddCommand(pInter,"testlog",testLogCmd,NULL,NULL); AddCommand(pInter,"MakeHMControl_ANSTO",MakeHMControl_ANSTO,NULL,NULL); // AddCommand(pInter,"MakeAsyncProtocol",AsyncProtocolFactory,NULL,NULL); // AddCommand(pInter,"MakeAsyncQueue",AsyncQueueFactory,NULL,NULL); AddCommand(pInter,"MakeMultiChan",AsyncQueueFactory,NULL,NULL); AddCommand(pInter,"MakeSafetyPLC",SafetyPLCFactory,NULL,NULL); AddCommand(pInter,"MakeLSSMonitor",LSSFactory,NULL,NULL); AddCommand(pInter,"MakeActionObject",ActionObjectFactory,NULL,NULL); AddCommand(pInter,"ANSTO_MakeHM",ANSTO_MakeHistMemory,NULL,NULL); AddCommand(pInter,"SICS_Site",SICS_Site,NULL,NULL); AddCommand(pInter,"SICS_Version",SICS_Version,NULL,NULL); AddCommand(pInter,"SICS_Revision",SICS_Revision,NULL,NULL); AddCommand(pInter, "sicslist", SicsList, NULL, NULL); AddCommand(pInter, "FileEvalGlob", MacroFileEvalGlob, NULL, NULL); AddCommand(pInter, "Valgrind", Ansto_Valgrind, NULL, NULL); AddCommand(pInter, "anstocapture", Ansto_Capture, NULL, NULL); /* * Tcl 8.5 has implemented the clock command in tcl rather then C. * This includes the same command, backported from Tcl 8.4 */ #if 0 printf("TCL interpreter %s safe\n", Tcl_IsSafe(InterpGetTcl(pServ->pSics)) ? "is" : "is not"); //TclClockInit(InterpGetTcl(pServ->pSics)); #else /* * from tclClock.c */ int Tcl_ClockObjCmd (ClientData client, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); /* * Tcl 8.5 has implemented the clock command in tcl rather than C. * This includes the same command, backported from Tcl 8.4 */ Tcl_CreateObjCommand(InterpGetTcl(pServ->pSics), "clock", Tcl_ClockObjCmd, NULL, NULL); #endif } /*---------------------------------------------------------------------*/ static void RemoveCommands(SicsInterp *pSics){ } /*-------------------------------------------------------------------*/ /*@null@*/ static pMotor CreateMotorAnsto(SConnection *pCon, int argc, char *argv[]) { MotorDriver *pDriver = NULL; pMotor pNew = NULL; char pBueffel[132]; /* create the motor */ strtolower(argv[1]); if(strcmp(argv[1],"dmc2280") == 0) { pDriver = (MotorDriver *)CreateDMC2280(pCon,argv[0],argv[2]); if(!pDriver){ return NULL; } pNew = MotorInit("DMC2280",argv[0],pDriver); if(!pNew) { sprintf(pBueffel,"ERROR:SITE: Failure to create motor %s",argv[1]); SCWrite(pCon,pBueffel,eError); return NULL; } pNew->pActionRoutine = DMC2280Action; } if(strcmp(argv[1],"asim") == 0) { pDriver = (MotorDriver *)CreateASIM(pCon,argv[0],argv[2]); if(!pDriver){ return NULL; } pNew = MotorInit("ASIM",argv[0],pDriver); if(!pNew) { sprintf(pBueffel,"ERROR:SITE: Failure to create motor %s",argv[1]); SCWrite(pCon,pBueffel,eError); return NULL; } pNew->pActionRoutine = SimAction; } return pNew; } /*-------------------------------------------------------------------*/ static pCounterDriver CreateCounterDriverAnsto(SConnection *pCon, int argc, char *argv[]){ pCounterDriver pDriver = NULL; strtolower(argv[2]); if(strcmp(argv[2],"anstomonitor") == 0) { pDriver = CreateMonCounter(pCon, argv[1], argv[3]); } else if (strcmp(argv[2], "anstocamera") == 0) { pDriver = CreateCam(pCon, argv[1], argv[3]); } if(!pDriver){ return NULL; } return pDriver; } /*-------------------------------------------------------------------*/ static HistDriver *CreateAnstoHistMem(char *name, pStringDict pOptions){ HistDriver *pNew = NULL; if(strcmp(name,"anstohttp") == 0){ pNew = CreateAnstoHttpDriver(pOptions); } return pNew; } /*-------------------------------------------------------------------*/ static pVelSelDriv CreateVelSelDriv(char *name, char *array, Tcl_Interp *pTcl){ pVelSelDriv pNew = NULL; return pNew; } /*-------------------------------------------------------------------*/ static pCodri CreateController(SConnection *pCon,int argc, char *argv[]){ pCodri pNew = NULL; if(strcmp(argv[0],"tcpdocho") == 0){ if(argc < 2){ SCWrite(pCon,"ERROR: insufficient number of arguments for creating TcpDoCho", eError); return NULL; } return NULL; } return pNew; } /*------------------------------------------------------------------*/ static pEVControl InstallEnvironmentController(SicsInterp *pSics, SConnection *pCon, int argc, char *argv[]){ int status; pEVControl pNew = NULL; pEVDriver pDriv = NULL; strtolower(argv[3]); /* Added code for new LH45 driver */ if(strcmp(argv[3],"lh45") == 0) { pDriv = CreateLH45Driver(argc-4,&argv[4]); if(pDriv){ pNew = CreateEVController(pDriv,argv[2],&status); if(pNew != NULL){ AddCommand(pSics,argv[2],LH45Wrapper,DeleteEVController, pNew); } } } /* Added code for new Lakeshore 340 driver */ if(strcmp(argv[3],"lakeshore340") == 0) { pDriv = CreateLAKESHORE340Driver(argc-4,&argv[4]); if(pDriv){ pNew = CreateEVController(pDriv,argv[2],&status); if(pNew != NULL){ AddCommand(pSics,argv[2],LAKESHORE340Wrapper,DeleteEVController, pNew); } } } /* Added code for new Lakeshore 340 driver */ if(strcmp(argv[3],"west4100") == 0) { pDriv = CreateWEST4100Driver(argc-4,&argv[4]); if(pDriv){ pNew = CreateEVController(pDriv,argv[2],&status); if(pNew != NULL){ AddCommand(pSics,argv[2],WEST4100Wrapper,DeleteEVController, pNew); } } } /* Added code for new NHQ 200 driver */ if(strcmp(argv[3],"nhq200") == 0) { pDriv = CreateNHQ200Driver(argc-4,&argv[4]); if(pDriv){ pNew = CreateEVController(pDriv,argv[2],&status); if(pNew != NULL){ NHQ200Register(pNew, pDriv); AddCommand(pSics,argv[2],NHQ200Wrapper,DeleteEVController, pNew); } } } /* Added code for new Oak Ridge High Voltage Power Supply driver */ if(strcmp(argv[3],"orhvps") == 0) { pDriv = CreateORHVPSDriver(argc-4,&argv[4]); if(pDriv){ pNew = CreateEVController(pDriv,argv[2],&status); if(pNew != NULL){ ORHVPSRegister(pNew, pDriv); AddCommand(pSics,argv[2],ORHVPSWrapper,DeleteEVController, pNew); } } } /* Added code for new LS340 LAKSHORE Temperature Controller 340 Driver */ if(strcmp(argv[3],"ls340") == 0) { pDriv = CreateLS340Driver(argc,argv); if(pDriv){ pNew = CreateEVController(pDriv,argv[2],&status); if(pNew != NULL){ LS340Register(pNew, pDriv); AddCommand(pSics,argv[2],LS340Wrapper,DeleteEVController, pNew); } } } return pNew; } /*-----------------------------------------------------------------*/ static int ConfigureScan(pScanData self, char *option){ if(!self) { return 0; } return 0; } /*--------------------------------------------------------------------*/ static void KillSite(void *site){ free(site); siteANSTO = NULL; } /*--------------------------------------------------------------------- The scheme here goes along the lines of the singleton design pattern ---------------------------------------------------------------------*/ pSite getSite(void) { if(siteANSTO == NULL) { siteANSTO = (pSite)malloc(sizeof(Site)); /* we cannot go on if we do not even have enough memory to allocate the site data structure */ assert(siteANSTO); /* initializing function pointers */ siteANSTO->AddSiteCommands = AddCommands; siteANSTO->RemoveSiteCommands = RemoveCommands; siteANSTO->CreateMotor = CreateMotorAnsto; siteANSTO->CreateCounterDriver = CreateCounterDriverAnsto; siteANSTO->CreateHistogramMemoryDriver = CreateAnstoHistMem; siteANSTO->CreateVelocitySelector = CreateVelSelDriv; siteANSTO->CreateControllerDriver = CreateController; siteANSTO->InstallEnvironmentController = InstallEnvironmentController; siteANSTO->ConfigureScan = ConfigureScan; siteANSTO->KillSite = KillSite; } return siteANSTO; } void broadcastPrintf(int iOut, char *fmt, ...) { va_list ap; char buf[256]; char *dyn; unsigned int l; int res; va_start(ap, fmt); l = vsnprintf(buf, sizeof buf, fmt, ap); va_end(ap); if (l >= sizeof buf) { /* we have probably a C99 conforming snprintf and need a larger buffer */ dyn = malloc(l+1); if (dyn != NULL) { va_start(ap, fmt); vsnprintf(dyn, l+1, fmt, ap); va_end(ap); ServerWriteGlobal(dyn, iOut); free(dyn); } } ServerWriteGlobal(buf, iOut); }