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

			C O U N T E R
			
    The SICS Interface to a single detector and his associated 
    monitors.


    Mark Koennecke,    January 1997

    Copyright:

    Labor fuer Neutronenstreuung
    Paul Scherrer Institut
    CH-5423 Villigen-PSI


    The authors hereby grant permission to use, copy, modify, distribute,
    and license this software and its documentation for any purpose, provided
    that existing copyright notices are retained in all copies and that this
    notice is included verbatim in any distributions. No written agreement,
    license, or royalty fee is required for any of the authorized uses.
    Modifications to this software may be copyrighted by their authors
    and need not follow the licensing terms described here, provided that
    the new terms are clearly indicated on the first page of each file where
    they apply.

    IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
    FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
    DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

    THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
    IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
    NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
    MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <time.h>
#include "fortify.h"
#include <string.h>
#include "countdriv.h"
#include "obdes.h"
#include "conman.h"
#include "interface.h"
#include "counter.h"
#include "fupa.h"
#include "devexec.h"
#include "status.h"
#include "event.h"
#include "splitter.h"
/*-------------------------------------------------------------------------*/
 /*
     The monitor callback data structure 
 */
     typedef struct {
                      float fPreset;
                      float fCurrent;
                      char *pName;
                    } MonEvent, *pMonEvent;       

/*--------------------------------------------------------------------------*/
   static int Halt(void *pData)
   {
      pCounter self = NULL;
      
      assert(pData);
      self = (pCounter)pData;
      
      return self->pDriv->Halt(self->pDriv);
   }
/*-----------------------------------------------------------------------*/
   static int StartCount(void *pData, SConnection *pCon)
   {
      pCounter self;
      char pBueffel[132];
      char pError[80];
      int iRet;
      int i;
      int iErr;
      time_t tX; 
            
      self = (pCounter)pData;
      assert(self);

    /* try at least three times to do it */
      for(i = 0; i < 3; i++)
      {
             iRet = self->pDriv->Start(self->pDriv);
             if(iRet == OKOK)
             {
               self->isUpToDate = 0;
               self->tStart = time(&tX);
               return iRet;
             }       
             else
             {
                iRet = self->pDriv->GetError(self->pDriv,&iErr,pError,79);
                sprintf(pBueffel,"WARNING: %s ",pError);
                SCWrite(pCon,pBueffel,eError);
                iRet = self->pDriv->TryAndFixIt(self->pDriv,iErr);
                if(iRet == COTERM)
                {
                  SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",eError);
                  SCSetInterrupt(pCon,eAbortBatch);
                  return HWFault;
                } 
             }
      }
      SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",eError);
      SCSetInterrupt(pCon,eAbortBatch);
      return HWFault;   
   }
/*-----------------------------------------------------------------------*/
   static int PauseCount(void *pData, SConnection *pCon)
   {
      pCounter self;
      char pBueffel[132];
      char pError[80];
      int iRet;
      int i;
      int iErr; 
            
      self = (pCounter)pData;
      assert(self);

    /* try at least three times to do it */
      for(i = 0; i < 3; i++)
      {
             iRet = self->pDriv->Pause(self->pDriv);
             if(iRet == OKOK)
             {
               self->isUpToDate = 0;
               return iRet;
             }       
             else
             {
                iRet = self->pDriv->GetError(self->pDriv,&iErr,pError,79);
                sprintf(pBueffel,"WARNING: %s ",pError);
                SCWrite(pCon,pBueffel,eError);
                iRet = self->pDriv->TryAndFixIt(self->pDriv,iErr);
                if(iRet == COTERM)
                {
                  SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",eError);
                  SCSetInterrupt(pCon,eAbortBatch);
                  return HWFault;
                } 
             }
      }
      SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",eError);
      SCSetInterrupt(pCon,eAbortBatch);
      return HWFault;   
   }
/*-----------------------------------------------------------------------*/
   static int ContinueCount(void *pData, SConnection *pCon)
   {
      pCounter self;
      char pBueffel[132];
      char pError[80];
      int iRet;
      int i;
      int iErr; 
            
      self = (pCounter)pData;
      assert(self);

    /* try at least three times to do it */
      for(i = 0; i < 3; i++)
      {
             iRet = self->pDriv->Continue(self->pDriv);
             if(iRet == OKOK)
             {
               self->isUpToDate = 0;
               return iRet;
             }       
             else
             {
                iRet = self->pDriv->GetError(self->pDriv,&iErr,pError,79);
                sprintf(pBueffel,"WARNING: %s ",pError);
                SCWrite(pCon,pBueffel,eError);
                iRet = self->pDriv->TryAndFixIt(self->pDriv,iErr);
                if(iRet == COTERM)
                {
                  SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",eError);
                  SCSetInterrupt(pCon,eAbortBatch);
                  return HWFault;
                } 
             }
      }
      SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",eError);
      SCSetInterrupt(pCon,eAbortBatch);
      return HWFault;   
   }
/*--------------------------------------------------------------------------*/     
 static int CheckCountStatus(void *pData, SConnection *pCon)
 {
      pCounter self = NULL;
      int i, iRet;
      int eCt;
      char pError[80], pBueffel[132];
      int iErr;
      float fControl;
      MonEvent sMon;
       
      self = (pCounter)pData;
      assert(self);
      assert(pCon);
 
      eCt = self->pDriv->GetStatus(self->pDriv,&fControl);
      if(eCt == HWFault)
      {
         iRet = self->pDriv->GetError(self->pDriv,&iErr,pError,79);
         sprintf(pBueffel,"WARNING: %s ",pError);
         SCWrite(pCon,pBueffel,eError);
         iRet = self->pDriv->TryAndFixIt(self->pDriv,iErr);
         if(iRet == COTERM)
         {
           SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",eError);
           SCSetInterrupt(pCon,eAbortBatch);
           SCSetError(pCon,eCt);
           return eCt;
         }  
         else
         {
           return HWBusy;
         }
      }
      sMon.fCurrent = fControl;
      sMon.fPreset  = self->pDriv->fPreset;
      sMon.pName = self->name;
      InvokeCallBack(self->pCall,MONITOR,&sMon);
      self->pDriv->fLastCurrent = fControl;
      return eCt;
 }
/*------------------------------------------------------------------------*/
  static int SaveCounterStatus(void *pData, char *name, FILE *fd)
  {
    pCounter self = NULL;
    char pBueffel[512];
    
    assert(pData);
    assert(fd);
    
    self = (pCounter)pData;
    
    sprintf(pBueffel,"# Counter %s\n",name);
    fputs(pBueffel,fd);
    sprintf(pBueffel,"%s SetPreset %f\n",name, self->pDriv->fPreset);
    fputs(pBueffel,fd);
    if(self->pDriv->eMode == eTimer)
    {
      sprintf(pBueffel,"%s SetMode Timer\n",name);
    }
    else
    {
      sprintf(pBueffel,"%s SetMode Preset\n",name);
    }
    fputs(pBueffel,fd);
    
    return 1;
  } 
/*------------------------------------------------------------------------*/
  static int TransferData(void *pData, SConnection *pCon)
  {
    pCounter self = NULL;
    int i, iRet;
    char pError[80];
    char pBueffel[132];
    int iCode;
    
    self = (pCounter)pData;
    assert(self);
    assert(pCon);

   /* try three times */
    for(i = 0; i < 3; i++)
    {
       iRet = self->pDriv->ReadValues(self->pDriv);
       if(iRet)
       {
         self->isUpToDate = 1;
         return OKOK;
       }
       else
       {
           self->pDriv->GetError(self->pDriv,&iCode,pError,79);
           sprintf(pBueffel,"WARNING: %s",pError);
           SCWrite(pCon,pBueffel,eError);
           iRet = self->pDriv->TryAndFixIt(self->pDriv,iCode);
           if(iRet == COTERM)
           {
             SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",eError);
             SCSetInterrupt(pCon,eAbortBatch);
             return HWFault;
           }
       }
    }
    SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",eError);
    SCSetInterrupt(pCon,eAbortBatch);    
    return HWFault;
  }
/*------------------------------------------------------------------------*/
  static void *CounterGetInterface(void *pData, int iID)
  {
    pCounter self = NULL;
    
    self = (pCounter)pData;
    assert(self);
    if(iID == COUNTID)
    {
      return self->pCountInt;
    }
    else if(iID == CALLBACKINTERFACE)
    {
      return self->pCall;
    }
    return NULL; 
  }
/*------------------------------------------------------------------------*/
  pCounter CreateCounter(char *name, pCounterDriver pDriv)
  {
      pCounter pRes = NULL;
      
      assert(pDriv);
      
      pRes = (pCounter)malloc(sizeof(Counter));
      if(!pRes)
      {
        return NULL;
      }
      pRes->pDes = CreateDescriptor("SingleCounter");
      if(!pRes->pDes)
      {
        free(pRes);
        return NULL;
      }
      /* initialize Descriptor functions */
      pRes->pDes->GetInterface = CounterGetInterface;
      pRes->pDes->SaveStatus  = SaveCounterStatus;

      /* initialise countable interface */
      pRes->pCountInt = CreateCountableInterface();
      if(!pRes->pCountInt)
      {
        DeleteDescriptor(pRes->pDes);
        free(pRes);
        return NULL;
      }
      pRes->pCountInt->StartCount = StartCount;
      pRes->pCountInt->CheckCountStatus = CheckCountStatus;
      pRes->pCountInt->TransferData = TransferData;
      pRes->pCountInt->Halt = Halt;
      pRes->pCountInt->Pause = PauseCount;
      pRes->pCountInt->Continue = ContinueCount;
      
      pRes->pCall = CreateCallBackInterface();
      
      pRes->pDriv = pDriv;
      pRes->isUpToDate = 1;
      pRes->iExponent = 0;
      pRes->name = strdup(name);
      return pRes;
  }
/*---------------------------------------------------------------------------*/
  void     DeleteCounter(void *pData)
  {
     pCounter self = NULL;
     
     assert(pData);
     self = (pCounter)pData;
     
     if(self->pDes)
     {
       DeleteDescriptor(self->pDes);
     }
     
     if(self->pCountInt)
     {
       free(self->pCountInt);
     }
     if(self->pCall)
     { 
       DeleteCallBackInterface(self->pCall);
     }
     
     if(self->name)
     {
       free(self->name);
     }
     if(self->pDriv)
     {
       if(strcmp(self->pDriv->type,"EL737") == 0)
       {
          KillEL737Counter(self->pDriv);
       }
       else if (strcmp(self->pDriv->type,"SIM") == 0)
       {
         KillSIMCounter(self->pDriv);
       }
       else
       {
         assert(0);
       }
     }
     free(self);
  }
/*-------------------------------------------------------------------------*/
  int DoCount(pCounter self, float fPreset, SConnection *pCon, 
             int iBlock)
  {
     int iRet;
     char pBueffel[132];
     Status eOld;
     
     assert(self);
     
     /* check authorisation */
     if(!SCMatchRights(pCon,usUser))
     {
       sprintf(pBueffel,"ERROR: you are not authorised to count");
       SCWrite(pCon, pBueffel, eError);
       return 0;
     }
     
     eOld = GetStatus();
     SetStatus(eCounting);
     
     /* set Preset */
     SetCounterPreset(self,fPreset);
     
     iRet = StartDevice(GetExecutor(),self->name,self->pDes,self,pCon,
                       self->pDriv->fPreset);
     if(!iRet)
     {
       SetStatus(eOld);
       SCWrite(pCon,"Counting aborted",eStatus);
       return 0;
     }                  
     
     /* continue only if in blocking mode */
     if(!iBlock)
     {
       return 1;
     }
     
     /* wait forever until done or interrupted */
     iRet = Wait4Success(GetExecutor());
     if(iRet == DEVINT)
     {
       SCWrite(pCon,"Counting aborted due to Interrupt",eStatus);
     }
     else if(iRet == DEVERROR)
     {
       SCWrite(pCon,"Counting finished with Problems",eStatus);
       iRet = 1; 
     }
     else
     {
       SCWrite(pCon,"Counting finished",eStatus);
       iRet = 1;
     }
     SetStatus(eOld);
     return iRet;
  }  
  
/*-------------------------------------------------------------------------*/
  int MakeCounter(SConnection *pCon, SicsInterp *pSics, void *pData,
                  int argc, char *argv[])
  {
    pCounter pNew = NULL;
    pCounterDriver pDriv = NULL;
    int iRet;
    char pBueffel[256];
    char **argx;
    FuPaResult pParse;
    FuncTemplate MakeTemplate[] = { 
                                   {"el737",3,{FUPATEXT,FUPAINT,FUPAINT}},
                                   {"sim",0,{0.0}}
                                };  

    assert(pCon);
    assert(pSics);

     argtolower(argc,argv);        
    /* parse function template */     
    argx = &argv[2]; /* 0 = MakeCounter, 1 = counter name */
    iRet = EvaluateFuPa((pFuncTemplate)&MakeTemplate,2,argc-2,argx,&pParse);
    if(iRet < 0) /* I/O error */
    {
      sprintf(pBueffel,"%s",pParse.pError);
      SCWrite(pCon,pBueffel,eError);
      return 0;
    }
    
    /* create driver depending on parse result */
    switch(iRet)
    {
      case 0: /* EL737 driver */
            pDriv = NewEL737Counter(argv[1],pParse.Arg[0].text,
                                    pParse.Arg[1].iVal,pParse.Arg[2].iVal);
            break;                        
      case 1: /* SIM */
            pDriv = NewSIMCounter(argv[1]);
            break;
      default:
            assert(0); /* internal error */                              
    }
    if(!pDriv)
    {
      sprintf(pBueffel,"ERROR: cannot create requested driver %s",
              argv[2]);
      SCWrite(pCon,pBueffel,eError);
      return 0;
    }
    
    /* create Counter and command */
    pNew = CreateCounter(argv[1],pDriv);
    if(!pNew)
    {
      sprintf(pBueffel,"ERROR: cannot create counter %s",
              argv[1]);
      SCWrite(pCon,pBueffel,eError);
      return 0;
    }
    iRet = AddCommand(pSics,argv[1],CountAction,DeleteCounter,(void *)pNew);
    if(!iRet)
    {
        sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[1]);
        SCWrite(pCon,pBueffel,eError);
        return 0;
    }
    return 1;
  }           
/* --------------------------------------------------------------------------*/
  int SetCounterMode(pCounter self, CounterMode eNew)
  {
    int i;
    
    assert(self);
    if(eNew == self->pDriv->eMode)
    {
      return 1;
    }
    
    if(eNew == eTimer)
    {
      for(i = 0; i < self->iExponent; i++)
      {
         self->pDriv->fPreset /= 10.;
      } 
    }
    if(eNew == ePreset)
    {
      for(i = 0; i < self->iExponent; i++)
      {
         self->pDriv->fPreset *= 10.;
      } 
    }
    self->pDriv->eMode = eNew;
    return 1;
  }
/*--------------------------------------------------------------------------*/  
  CounterMode GetCounterMode(pCounter self)
  {
    assert(self);
    return self->pDriv->eMode;
  }
/*------------------------------------------------------------------------*/
  int GetNMonitor(pCounter self)
  {
    assert(self);
    return self->pDriv->iNoOfMonitors;
  }  
/*------------------------------------------------------------------------*/  
  int SetCounterPreset(pCounter self, float fVal)
  {
     int i;
     
     assert(self);
     
     if(fVal < .0)
     {
        return 0;
     }
     if(GetCounterMode(self) == ePreset)
     {
        for(i = 0; i < self->iExponent;i++)
        {
          fVal *= 10.;
        }
        fVal = nintf(fVal);
     }
     self->pDriv->fPreset = fVal;
     return 1;
  }
/*------------------------------------------------------------------------*/
  float GetCounterPreset(pCounter self)
  {
     int i;
     float fVal;
     
     assert(self);
     
     fVal = self->pDriv->fPreset;
     if(self->pDriv->eMode == ePreset)
     {
       for(i = 0; i < self->iExponent; i++)
       {
         fVal /= 10.;
       }
     }
     return fVal;
  }
/*-----------------------------------------------------------------------*/  
  long GetCounts(pCounter self, SConnection *pCon)
  {
     assert(self);
     if(!self->isUpToDate)
     {
       self->pCountInt->TransferData(self,pCon);
     }
     return self->pDriv->lCounts[0];
  }
/*------------------------------------------------------------------------*/  
  long GetMonitor(pCounter self, int iNum, SConnection *pCon)
  {
     assert(self);

     if(!self->isUpToDate)
     {
       self->pCountInt->TransferData(self,pCon);
     }
     if( (iNum < 0) || (iNum > self->pDriv->iNoOfMonitors) )
     {
       return -1L;
     }
     else
     {
       return self->pDriv->lCounts[iNum];
     }
  }
/*------------------------------------------------------------------------*/  
  float GetCountTime(pCounter self,SConnection *pCon)
  {
     assert(self);

     if(!self->isUpToDate)
     {
       self->pCountInt->TransferData(self,pCon);
     }
     return self->pDriv->fTime;
  }
/*----------------------------------------------------------------------*/
  static int isAuthorised(SConnection *pCon, int iCode)
  {
    char pBueffel[132];
    
    if(!SCMatchRights(pCon,iCode))
    {
       sprintf(pBueffel,"ERROR: you are not authorised to count");
       SCWrite(pCon, pBueffel, eError);
       return 0;
    }
    return 1;
  }  
/*-----------------------------------------------------------------------*/
  static int CounterInterest(int iEvent, void *pEvent, void *pUser)
  {
     SConnection *pCon = NULL;
     pMonEvent pMon = NULL;
     char pBueffel[512];
     
     if(iEvent != MONITOR)
     {
       return 0;
     }
     
     pCon = (SConnection *)pUser;
     pMon = (pMonEvent)pEvent;
     assert(pCon);
     assert(pMon);
     sprintf(pBueffel,"%s.CountStatus = %f %d",pMon->pName,pMon->fPreset,
             (int)nintf(pMon->fCurrent));
     SCWrite(pCon,pBueffel,eWarning);
     return 1;        
  }  
/*-----------------------------------------------------------------------*/  
  
  int CountAction(SConnection *pCon, SicsInterp *pSics, void *pData,
                  int argc, char *argv[])
  {
    pCounter self = NULL;
    int iRet, iRet2;
    FuPaResult PaRes;
    char pBueffel[256], pError[80];
    char **argx;
    float fVal;
    long lVal;
    long lID;
    CounterMode eMode;
    FuncTemplate ActionTemplate[] = {
                                      {"count",1,{FUPAFLOAT} },
                                      {"getpreset",0,{0.0} },
                                      {"setpreset",1,{FUPAFLOAT}},
                                      {"getmode",0,{0,0}},
                                      {"setmode",1,{FUPATEXT}},
                                      {"getcounts",0,{0,0}},
                                      {"getmonitor",1,{FUPAINT,0}},
                                      {"setexponent",1,{FUPAINT,0}},
                                      {"getexponent",0,{0,0}},
                                      {"interest",0,{0,0}},
                                      {"uninterest",0,{0,0}},
                                      {"status",0,{0,0}},
                                      {"gettime",0,{0,0}},
                                      {"countnb",1,{FUPAFLOAT} },
                                      {"getthreshold",1,{FUPAINT}},
                                      {"setthreshold",2,{FUPAINT,FUPAFLOAT}},
                                      {"stop",0,{0,0}},
                                      {"mode",1,{FUPAOPT}},
                                      {"preset",1,{FUPAOPT}},
                                      {"send",0,{0,0}}
                                    };
   char *pMode[] = {
                    "timer",
                    "monitor",
                    NULL
                   };
                                               
   self = (pCounter)pData;
   assert(self);
   assert(pCon);
   assert(pSics);                        
                                    
   /* parse function args */
   argtolower(argc,argv);
   argx = &argv[1];
   iRet = EvaluateFuPa((pFuncTemplate)&ActionTemplate,20,argc-1,argx,&PaRes);
   if(iRet < 0)
   {
      sprintf(pBueffel,"%s",PaRes.pError);
      SCWrite(pCon,pBueffel,eError);
      return 0;
   }
   
   /* do something! */
   switch(iRet)
   {
     case 0: /* Count */
            return DoCount(self,PaRes.Arg[0].fVal,pCon,1);
            break;
     case 1: /* GetPreset */       
            fVal = GetCounterPreset(self);
            sprintf(pBueffel,"%s.Preset = %f",argv[0],fVal);
            SCWrite(pCon,pBueffel,eValue);
            return 1;
            break;
     case 2: /* Set Preset */
             if(isAuthorised(pCon,usUser))
             {
               iRet2 = SetCounterPreset(self,PaRes.Arg[0].fVal);
               if(iRet2)
                   SCSendOK(pCon);
               return iRet2;    
             }       
             else
             {
               return 0;
             }
             break;
      case 3: /* GetMode */
             eMode = GetCounterMode(self);
             if(eMode == eTimer)
             {
                sprintf(pBueffel,"%s.Mode = Timer",argv[0]);
             }
             else
             {
               sprintf(pBueffel,"%s.Mode = Monitor",argv[0]);
             }
             SCWrite(pCon,pBueffel,eValue);
             return 1;
             break;   
      case 4: /* Set Mode */
             if(isAuthorised(pCon,usUser))
             {
               if(strcmp(PaRes.Arg[0].text,"timer") == 0)
               {
                 SetCounterMode(self,eTimer);
                 SCSendOK(pCon);
                 return 1;
               }
               else if(strcmp(PaRes.Arg[0].text,"monitor") == 0)
               {
                  SetCounterMode(self,ePreset);
                  SCSendOK(pCon);
                  return 1;
               }
               else
               {
                 sprintf(pBueffel,"ERROR: %s not recognized as valid counter mode",
                         PaRes.Arg[0].text);
                 SCWrite(pCon,pBueffel,eError);
                 return 0;         
               }
             }
             else
             {
               return 0;
             }    
      case 5: /* GetCounts */
             lVal = GetCounts(self,pCon);
             sprintf(pBueffel,"%s.Counts = %ld",argv[0],lVal);
             SCWrite(pCon,pBueffel,eValue);
             return 1;             
                    
      case 6: /* GetMonitor */
             lVal = GetMonitor(self,PaRes.Arg[0].iVal,pCon);
             if(lVal < 0) 
             {
               sprintf(pBueffel,"ERROR: %d out of range for monitors",
                      PaRes.Arg[0].iVal);
               SCWrite(pCon,pBueffel,eError);
               return 0;         
             }
             sprintf(pBueffel,"%s.Monitor %d = %ld",argv[0],PaRes.Arg[0].iVal,
                     lVal);
             SCWrite(pCon,pBueffel,eValue);
             return 1;             
      case 7: /* SetExponent */
             self->iExponent = PaRes.Arg[0].iVal;
             SCSendOK(pCon);
             return 1;
      case 8: /* GetExponent */
             sprintf(pBueffel,"%s.Exponent = %d",argv[0], self->iExponent);
             SCWrite(pCon,pBueffel,eValue);
             return 1;       
      case 9: /* interest */
              lID = RegisterCallback(self->pCall, MONITOR, CounterInterest,
                                                    pCon, NULL);
              SCRegister(pCon,pSics, self->pCall,lID);
              SCSendOK(pCon);
              return 1;
      case 10: /* uninterest */
              RemoveCallback2(self->pCall,pCon);
              SCSendOK(pCon);
              return 1;            
      case 11: /* status */
              if(GetCounterMode(self) == ePreset)
	      {
                   sprintf(pBueffel,"%s.CountStatus = %d %d Beam: %ld E6",
                               argv[0],
                               (int)nintf(self->pDriv->fPreset),
                               (int)nintf(self->pDriv->fLastCurrent),
                               GetMonitor(self,4,pCon)/100000);
              }
              else
	      {
                   sprintf(pBueffel,"%s.CountStatus = %8.2f %8.2f Beam %ld E6",
                               argv[0],
                               self->pDriv->fPreset,
                               self->pDriv->fLastCurrent,
                               GetMonitor(self,4,pCon)/100000);
              }
              SCWrite(pCon,pBueffel,eWarning);
              return 1;        
      case 12: /* gettime */
              fVal = GetCountTime(self,pCon);
              sprintf(pBueffel,"%s.CountTime = %f",argv[0],fVal);
              SCWrite(pCon,pBueffel,eValue);
              return 1;                                                                      
      case 13:
            /* countnb, non blocking count */
            return DoCount(self,PaRes.Arg[0].fVal,pCon,0);
            break;
      case 14:
	    /* get threshold value */
            iRet = self->pDriv->Get(self->pDriv,PARTHRESHOLD,
                                    PaRes.Arg[0].iVal,&fVal);
            if(iRet <= 0)
	    {
              self->pDriv->GetError(self->pDriv,&iRet,
                                    pError,79);
              sprintf(pBueffel,"ERROR: %s",pError);
              SCWrite(pCon,pBueffel,eError);
              return 0;
            }
            else
	    {
              sprintf(pBueffel,"%s.threshold%1.1d = %f",
                      argv[0],PaRes.Arg[0].iVal,fVal);
              SCWrite(pCon,pBueffel,eValue);
              return 1;
            }
            break;
      case 15:
            if(!SCMatchRights(pCon,usMugger))
            {
               SCWrite(pCon,
                 "ERROR: Insufficient privilege to set threshold",eError);
               return 0;  
            }
	    /* set threshold value */
            iRet = self->pDriv->Set(self->pDriv,PARTHRESHOLD,
                                    PaRes.Arg[0].iVal,PaRes.Arg[1].fVal);
            if(iRet <= 0)
	    {
              self->pDriv->GetError(self->pDriv,&iRet,
                                    pError,79);
              sprintf(pBueffel,"ERROR: %s",pError);
              SCWrite(pCon,pBueffel,eError);
              return 0;
            }
            else
	    {
              SCSendOK(pCon);
              return 1;
            }
            break;
      case 16:
	    /* stop */
            if(!SCMatchRights(pCon,usUser))
	    {
               return 0;
            }
            self->pCountInt->Halt(self);
            SCSendOK(pCon);
            return 1;
      case 17:
	    /* mode */
	    if(PaRes.Arg[0].iVal) /* set case */
	    {
               if(isAuthorised(pCon,usUser))
               {
                 if(strcmp(PaRes.Arg[0].text,"timer") == 0)
                 {
                    SetCounterMode(self,eTimer);
                    SCSendOK(pCon);
                    return 1;
                  }
                  else if(strcmp(PaRes.Arg[0].text,"monitor") == 0)
                  {
                    SetCounterMode(self,ePreset);
                    SCSendOK(pCon);
                    return 1;
                  }
                  else
                  {
                      sprintf(pBueffel,
                          "ERROR: %s not recognized as valid counter mode",
                         PaRes.Arg[0].text);
                      SCWrite(pCon,pBueffel,eError);
                      return 0;         
                  }
	       }
            }
            else /* get case */
	    {
               eMode = GetCounterMode(self);
               if(eMode == eTimer)
               {
                  sprintf(pBueffel,"%s.Mode = Timer",argv[0]);
               }
               else
               {
                 sprintf(pBueffel,"%s.Mode = Monitor",argv[0]);
               }
               SCWrite(pCon,pBueffel,eValue);
               return 1;
               break;   
            }
            break; 
      case 18: /* preset */
 	    if(PaRes.Arg[0].iVal) /* set case */
	    {
                if(isAuthorised(pCon,usUser))
                {
                   iRet2 = SetCounterPreset(self,PaRes.Arg[0].fVal);
                   if(iRet2)
                      SCSendOK(pCon);
                   return iRet2;    
                }       
                else
                {
                   return 0;
                }
            }
            else /* read case */
	    {
                fVal = GetCounterPreset(self);
                sprintf(pBueffel,"%s.Preset = %f",argv[0],fVal);
                SCWrite(pCon,pBueffel,eValue);
                return 1;
            }
            break;
      case 19:  /* send */
	/* only manager may use this */
            if(!SCMatchRights(pCon,usMugger))
	    {
               return;
            }
            Arg2Text(argc-2,&argv[2],pError,79);
            iRet = self->pDriv->Send(self->pDriv,pError,pBueffel,255);
            if(iRet == 1)
	    {
               SCWrite(pCon,pBueffel,eValue);
               return 1;
            } 
            else 
	    {
               self->pDriv->GetError(self->pDriv,&iRet,pError,79);
               SCWrite(pCon,pError,eError);
               return 0;
            }         
            break;
      default:
             assert(0); /* internal error */       
   }
   return 0;
 }

                          
