/*--------------------------------------------------------------------------
                               S C A N
                               
    Implementation file for the SICS scan command. 
    
    
    Mark Koennecke, October 1997
    
    copyright: see copyright.h
----------------------------------------------------------------------------*/
#include "sics.h"
#include <stdio.h>
#include <arpa/inet.h>
#include <tcl.h>
#include <math.h>
#include "fortify.h"
#include "sdynar.h"
#include "status.h"
#include "sicsvar.h"
#include "counter.h"
#include "scan.h"
#include "scan.i"
#include "integrate.h"
#include "udpquieck.h"
#include "splitter.h"
#include "danu.h"
#include "amorscan.h"
#include "motor.h"

extern void  SNXFormatTime(char *pBuffer, int iLen);
  /*
      from nxdata.c
  */  
/*------------------------------------------------------------------------*/
  char *ScanMakeFileName(SicsInterp *pSics, SConnection *pCon, char *pExt)
  {
      pSicsVariable pPath = NULL, pPref = NULL, pEnd = NULL;
      char *pRes = NULL;
      int iLen, iNum, iYear;
      char pNumText[10];
      CommandList *pCom = NULL;
      
      /* Try, get all the Variables */
      pPath = FindVariable(pSics,"sicsdatapath");
      pPref = FindVariable(pSics,"sicsdataprefix");
      pCom  = FindCommand(pSics,"sicsdatanumber");
      
      if( (!pPath) || (!pPref) || (!pCom))
      {
         SCWrite(pCon,
           "ERROR: cannot read variables for automatic data file name creation",
            eError);
         SCWrite(pCon,"ERROR: This is a VERY, VERY, VERY serious installation problem",
                 eError);
         SCWrite(pCon,"ERROR: your data will be dumped into emergency.hdf",eError); 
         return strdup("emergency.hdf");           
      }

      /* find length */
      iLen = strlen(pPath->text);
      iLen += strlen(pPref->text);
      iLen += 8; /* for number + year */
      iLen += 3;
      iLen += 10; /* safety margin */ 
      
      /* allocate memory */
      pRes = (char *)malloc(iLen*sizeof(char));
      if(!pRes)
      {
         SCWrite(pCon,"ERROR: no memory in SNXMakeFileName",eError);
         return NULL;
      }     
      memset(pRes,0,iLen);
      
      /* build the filename */
      strcpy(pRes,pPath->text);
      strcat(pRes,pPref->text);
      iNum = IncrementDataNumber(pCom->pData,&iYear);
      if(iNum < 0)
      {
        SCWrite(pCon,"ERROR: cannot increment data number!",eError);
        SCWrite(pCon,"ERROR: your data will be dumped to emergency.dat",eError);
        free(pRes);
        return strdup("emergency.dat");
      }
      sprintf(pNumText,"%5.5d",iNum);
      strcat(pRes,pNumText);
      sprintf(pNumText,"%4.4d",iYear);
      strcat(pRes,pNumText);
      strcat(pRes,pExt);
 
     return pRes;
  }

/*--------------------- VarEntry Management --------------------------------*/
  static void DeleteVarEntry(void *pData)
  {
     pVarEntry pVar = NULL;
     
     pVar = (pVarEntry)pData;
     
     assert(pVar);
     
     if(pVar->fData)
     {
       free(pVar->fData);
     }
     free(pVar);
  }
/*---------------------------------------------------------------------------*/
  static void DeleteCountEntry(void *pData)
  {
     free(pData);
  }
/*--------------------------------------------------------------------------*/
  static int DummyWrite(pScanData self)
  {
    return 1;
  }
/*--------------------------------------------------------------------------*/
  static int DummyWrite2(pScanData self, int iPoint)
  {
    return 1;
  }
/*---------------------------------------------------------------------------*/
  static int WriteHeader(pScanData self)
  {
     int i, iRet;
     FILE *fd;
     char pBuffer[512], pError[512], *pPtr, *pName;
     CommandList *pCom = NULL;
     pSicsVariable pVar = NULL;
     pDummy        pDum = NULL;
     pIDrivable    pDriv = NULL;
     float fVal;
     pMotor pMot = NULL;
     pVarEntry pScanVar = NULL;
     void *pVoid = NULL;
     
     assert(self->pSics);
     assert(self->pCon);
     
     /* open data file */
     self->fd = fopen(self->pFile,"w");
     if(!self->fd)
     {
       SCWrite(self->pCon,"ERROR: cannot write data file",eError);
       return 0;
     }
     
     /* open header description file */
     fd = fopen(self->pHeaderFile,"r");
     if(!fd)
     {
       SCWrite(self->pCon,"ERROR: cannot open header description file",eError);
       return 0;
     }
     
     /* loop through description file and act along the way */
     while(fgets(pBuffer,511,fd) != NULL)
     {
        pPtr = strstr(pBuffer,"!!VAR(");
        if(pPtr) /* handle a Sics variable */
        {
          /* extract the name */
          pName = pPtr + 6; /* first char of name */
          *pPtr = '\0'; /* this is the starter of the line */
          pPtr = pName;
          while( (*pPtr != '\0') && (*pPtr != ')') )
          {
            pPtr++;
          }
          *pPtr = '\0';
          /* find the variable */
          pCom = FindCommand(self->pSics,pName);
          if(!pCom)
          {
            sprintf(pError,"ERROR: variable %s NOT found",pName);
            SCWrite(self->pCon,pError,eError);
            continue; 
          }
          pVar = (pSicsVariable)pCom->pData;
          if(!pVar)
          {
            sprintf(pError,"ERROR: variable %s NOT found",pName);
            SCWrite(self->pCon,pError,eError);
            continue; 
          }
          switch(pVar->eType)
          {
             case veFloat:
                  sprintf(pError,"%f",pVar->fVal);
                  break;
             case veInt:
                  sprintf(pError,"%d",pVar->iVal);
                  break;
             case veText:
                  sprintf(pError,"%s",pVar->text);
                  break;          
          }
          /* finally write  */
          fprintf(self->fd,"%s %s\n",pBuffer,pError);
          continue;
        }/* end variable */
/*------- Drivable */        
        pPtr = strstr(pBuffer,"!!DRIV(");
        if(pPtr) 
        {
          /* extract the name */
          pName = pPtr + 7; /* first char of name */
          *pPtr = '\0'; /* this is the starter of the line */
          pPtr = pName;
          while( (*pPtr != '\0') && (*pPtr != ')') )
          {
            pPtr++;
          }
          *pPtr = '\0';
          /* find the variable */
          pCom = FindCommand(self->pSics,pName);
          if(!pCom)
          {
            sprintf(pError,"ERROR: variable %s NOT found",pName);
            SCWrite(self->pCon,pError,eError);
            continue; 
          }
          pDum = (pDummy)pCom->pData;
          if(!pDum)
          {
            sprintf(pError,"ERROR: variable %s is NOT drivable",pName);
            SCWrite(self->pCon,pError,eError);
            continue;
          }
          pDriv = (pIDrivable)pDum->pDescriptor->GetInterface(pDum,DRIVEID);
          if(!pDriv)
          {
            sprintf(pError,"ERROR: variable %s is NOT drivable",pName);
            SCWrite(self->pCon,pError,eError);
            continue;
          }
          fVal = pDriv->GetValue(pDum,self->pCon);
          fprintf(self->fd,"%s %f\n",pBuffer,fVal);
          continue;
        } /* end drive */
/*------- zero point */        
        pPtr = strstr(pBuffer,"!!ZERO(");
        if(pPtr) 
        {
          /* extract the name */
          pName = pPtr + 7; /* first char of name */
          *pPtr = '\0'; /* this is the starter of the line */
          pPtr = pName;
          while( (*pPtr != '\0') && (*pPtr != ')') )
          {
            pPtr++;
          }
          *pPtr = '\0';
          /* find the motor */
          pMot = FindMotor(self->pSics,pName);
          if(!pMot)
          {
            sprintf(pError,"ERROR: motor %s NOT found",pName);
            SCWrite(self->pCon,pError,eError);
            continue; 
          }
          iRet = MotorGetPar(pMot,"softzero",&fVal);
          if(!iRet)
	  {
            SCWrite(self->pCon,"ERROR: failed to read zero point",eError);
            continue;
          }
          fprintf(self->fd,"%s %f\n",pBuffer,fVal);
          continue;
        } /* end zero point */
/* ------- date */
        pPtr = strstr(pBuffer,"!!DATE!!");
        if(pPtr)
        {
          *pPtr = '\0';
          SNXFormatTime(pError,511);
          fprintf(self->fd,"%s %s\n",pBuffer,pError);
          continue;
        }
/*-------- filename */        
        pPtr = strstr(pBuffer,"!!FILE!!");
        if(pPtr)
        {
          *pPtr = '\0';
          fprintf(self->fd,"%s %s\n",pBuffer,self->pFile);
          continue;
        }
/*------------ scanzero */
        pPtr = strstr(pBuffer,"!!SCANZERO!!");
        if(pPtr)
        {
           *pPtr = '\0';
           /* write zero point of first scan variable if motor */
           DynarGet(self->pScanVar,0,&pVoid);
           pScanVar = (pVarEntry)pVoid;
           if(pScanVar)
           {
                pMot = NULL;
                pMot = FindMotor(self->pSics,pScanVar->Name);
                if(pMot != NULL)
	        {
                  MotorGetPar(pMot,"softzero",&fVal);
                  fprintf(self->fd,"%s zero = %8.3f\n",pScanVar->Name, fVal);
                }        
            }
        }
/* --------- plain text */
        fprintf(self->fd,"%s",pBuffer);        
     } /* end while */


     /* remember position for seeking to it for writing data */
     self->lPos = ftell(self->fd);

     fclose(fd);
     return 1;
  } 
/*--------------------------------------------------------------------------*/
  static int WriteScanPoints(pScanData self, int iPoint)
  {
    int i, i2;
    char pLine[512], pItem[30], pInfo[512];
    pVarEntry pVar = NULL;
    pCountEntry pData = NULL;
    void *pPtr = NULL;
    
    assert(self->pCon);
    assert(self->pSics);

    /* reopen file */
    self->fd = fopen(self->pFile,"r+");
    if(!self->fd)
    { 
         SCWrite(self->pCon,
                 "ERROR: Failed to reopen scan file, aborting scan",
                       eError);
         return 0;        
    }

    
    /* jump to end of header */
    fseek(self->fd,self->lPos, SEEK_SET);
    if(self->iChannel != 0)
    {
      fprintf(self->fd,"WARNING: Scanning monitor %d\n",self->iChannel);
    }
    
    /* make the data header */
    sprintf(pLine,"%-5s","NP");
    strcpy(pInfo,"Scanning Variables: ");
    for(i = 0; i < self->iScanVar;i++)
    {
      DynarGet(self->pScanVar,i,&pPtr);
      pVar = (pVarEntry)pPtr;
      if(pVar)
      {
        sprintf(pItem,"%-9.9s ",pVar->Name);
        strcat(pLine,pItem);
        sprintf(pItem,"%s, ",pVar->Name);
        strcat(pInfo,pItem);
      }
    }
    strcat(pLine,"Counts      ");
    strcat(pLine,"Monitor1    ");
    strcat(pLine,"Monitor2    ");
    strcat(pLine,"Monitor3    ");
    strcat(pLine,"Time  ");
    sprintf(pItem,"\n%d Points,",self->iNP);
    strcat(pInfo,pItem);
    if(self->iMode == eTimer)
    {
       strcat(pInfo," Mode: Timer,");
    }
    else
    {
      strcat(pInfo," Mode: Monitor,");
    }
    sprintf(pItem," Preset %f",self->fPreset);
    strcat(pInfo,pItem);
    fprintf(self->fd,"%s\n",pInfo);    
    fprintf(self->fd,"%s\n",pLine);
    
    /* now the scan points */
    for(i = 0; i < self->iCounts; i++)
    {
      sprintf(pLine,"%-5d",i);
      /* print vars */
      for(i2 = 0; i2 < self->iScanVar; i2++)
      {
         DynarGet(self->pScanVar,i2,&pPtr);
         pVar = (pVarEntry)pPtr;
         if(pVar)
         {
           sprintf(pItem,"%-10.3f",pVar->fData[i]);
           strcat(pLine,pItem);
         }
      }
      /* print Counts & Monitor */
      DynarGet(self->pCounts,i,&pPtr);
      pData = (pCountEntry)pPtr;
      if(pData)
      {
        sprintf(pItem,"%-12ld",pData->lCount);
        strcat(pLine,pItem);
        sprintf(pItem,"%-12ld",pData->Monitors[0]);
        strcat(pLine,pItem);
        sprintf(pItem,"%-12ld",pData->Monitors[1]);
        strcat(pLine,pItem);
        sprintf(pItem,"%-12ld",pData->Monitors[2]);
        strcat(pLine,pItem);
        sprintf(pItem,"%-6.1f",pData->fTime);
        strcat(pLine,pItem);
      }
      fprintf(self->fd,"%s\n",pLine);
    }
   
    /* done */
    fprintf(self->fd,"END-OF-DATA\n");
    fclose(self->fd);
    self->fd = NULL;
    return 1;
  }          
/*---------------------------------------------------------------------------*/
  static void *ScanInterface(void *pData, int iInter)
  {
     pScanData self = NULL;
     
     self = (pScanData)pData;
     assert(self);
     
     if(iInter == CALLBACKINTERFACE)
     {
       return self->pCall;
     }
     return NULL;  
  }  
/*-------------------------------------------------------------------------*/
  static int ScanDrive(pScanData self, int iPoint);
  static int ScanCount(pScanData self, int iPoint);
  static int CollectScanData(pScanData self, int iPoint);
/*--------------------------------------------------------------------------*/
  pScanData CreateScanObject(char *pRecover, char *pHeader,pCounter pCount)
  {
     pScanData pNew = NULL;
     
     pNew = (pScanData)malloc(sizeof(ScanData));
     if(!pNew)
     {
       return NULL;
     }
     memset(pNew,0,sizeof(ScanData));
     
     /* create an ObjectDescriptor */
     pNew->pDes = CreateDescriptor("ScanObject");
     if(!pNew->pDes)
     {
       free(pNew);
       return NULL;
     }
     pNew->pDes->GetInterface = ScanInterface;
     
     /* allocate the dynamic arrays */
     pNew->pScanVar = CreateDynar(0,10,10,DeleteVarEntry);
     pNew->pCounts = CreateDynar(0,10,10,DeleteCountEntry);
     if( (!pNew->pScanVar) || (!pNew->pCounts) )
     {
       DeleteDescriptor(pNew->pDes);
       free(pNew);
       return NULL;
     }
     
     /* make a callback interface */
     pNew->pCall = CreateCallBackInterface();
     if(!pNew->pCall)
     {
       DeleteScanObject(pNew);
       return NULL;
     } 
     
     /* assign various things */
     if(pRecover)
     {
        strcpy(pNew->pRecover,pRecover);
     }
     if(pHeader)
     {   
        strcpy(pNew->pHeaderFile,pHeader);
     }   
     pNew->iMode = eTimer;
     pNew->fPreset = 10.;
     strcpy(pNew->pCounterName,pCount->name);
     pNew->pCounterData = pCount;
     pNew->WriteHeader = WriteHeader;
     pNew->WriteScanPoints = WriteScanPoints;
     pNew->ScanDrive = ScanDrive;
     pNew->ScanCount = ScanCount;
     pNew->CollectScanData = CollectScanData;
     strcpy(pNew->ext,".dat");
     pNew->iWindow = 6;
     
     return pNew;
  }
/*---------------------------------------------------------------------------*/
  void DeleteScanObject(void *pData)
  {
    pScanData self = NULL;
    
    self = (pScanData)pData;
    if(!self)
    {
      return;
    }
    if(self->pDes)
    {
      DeleteDescriptor(self->pDes);
    }
    if(self->pCall)
    {
      DeleteCallBackInterface(self->pCall);
    }
    if(self->pScanVar)
    {
       DeleteDynar(self->pScanVar);
    }
    if(self->pCounts)
    {
       DeleteDynar(self->pCounts);
    }
    if(self->pCommand)
    {
       free(self->pCommand);
    }
    free(self);
  }  
/*------------------------------------------------------------------------*/
  int ResetScanFunctions(pScanData self)
  {
     assert(self);

     self->WriteHeader = WriteHeader;
     self->WriteScanPoints = WriteScanPoints;
     self->ScanDrive = ScanDrive;
     self->ScanCount = ScanCount;
     self->CollectScanData = CollectScanData;
     strcpy(self->ext,".dat");

     return 1;
  }
/*-------------------------------------------------------------------------*/
  int AddScanVar(pScanData self, SicsInterp *pSics, SConnection *pCon,
                 char *name, float fStart, float fStep)
  {
     CommandList *pCom = NULL;
     pIDrivable  pDriv = NULL;
     pDummy      pData = NULL;
     VarEntry    pVar;
     char pBueffel[512];
     
     if(self->iActive)
     {
       SCWrite(pCon,"ERROR: cannot change parameters while scan is running",eError);
       return 0;
     }
     
     /* find the thing */
     pCom = FindCommand(pSics,name);
     if(!pCom)
     {
        sprintf(pBueffel,"ERROR: Cannot find variable %s to scan",name);
        SCWrite(pCon,pBueffel,eError);
        return 0;
     }
     pData = (pDummy)pCom->pData;
     if(!pData)
     {
        sprintf(pBueffel,"ERROR: Cannot find data for variable %s",name);
        SCWrite(pCon,pBueffel,eError);
        return 0;
     }
     pDriv = pData->pDescriptor->GetInterface(pData,DRIVEID);
     if(!pDriv)
     {
        sprintf(pBueffel,"ERROR: variable %s is NOT driveable and cannot be scanned",name);
        SCWrite(pCon,pBueffel,eError);
        return 0;
     }

     /* got everything, fill in the VarEntry structure */
     strcpy(pVar.Name,name);
     pVar.pInter = pDriv;
     pVar.pObject = pData;
     pVar.fStart = fStart;
     pVar.fStep =  fStep;
     pVar.fData  = NULL;
     
     /* put it away */
     DynarPutCopy(self->pScanVar,self->iScanVar,&pVar,sizeof(VarEntry));
     self->iScanVar++;
     
     return 1; 
  }         
/*--------------------------------------------------------------------------*/
  int ClearScanVar(pScanData self)
  {
     if(self->iActive)
     {
       return 0;
     }

     self->iScanVar = 0;
     return 1;
  }
/*-------------------------------------------------------------------------*/
  struct RecoHead {
           int iScanVar;
           int iNP;
           int iMode;
           float fPreset;
           int iCounts;
           int iChannel;
         };

  struct VarHead {
           char pName[256];
           float fStart;
           float fStep;
         };               
/*--------------------------------------------------------------------------*/
  static int WriteRecover(pScanData self)
  {
     FILE *fd;
     struct RecoHead sHead;
     struct VarHead  sVar;
     void *pData;
     pVarEntry pVar = NULL;
     pCountEntry   pCount = NULL;
     int i;
     
     fd = fopen(self->pRecover,"wb");
     if(!fd)
     {
       return 0;
     }
     
     /* write Header */
     sHead.iScanVar = self->iScanVar;
     sHead.iNP      = self->iNP;
     sHead.iMode    = self->iMode;
     sHead.fPreset  = self->fPreset;
     sHead.iCounts  = self->iCounts;
     sHead.iChannel = self->iChannel;
     fwrite(&sHead,sizeof(struct RecoHead),1,fd);
     
     /* write scan vars */
     for(i = 0; i < self->iScanVar; i++)
     {
       DynarGet(self->pScanVar,i,&pData);
       pVar = (pVarEntry)pData;
       if(pVar)
       {
          strcpy(sVar.pName,pVar->Name);
          sVar.fStep  = pVar->fStep;
          sVar.fStart = pVar->fStart;
          fwrite(&sVar,sizeof(struct VarHead),1,fd);
          fwrite(pVar->fData,sizeof(float),sHead.iNP,fd);
       }
       pData = NULL;
     } 
     
     /* write counts */
     for(i = 0; i < self->iCounts; i++)
     {
        DynarGet(self->pCounts,i,&pData);
        pCount = (pCountEntry)pData;
        if(pCount)
        {
            fwrite(pCount,sizeof(CountEntry),1,fd);
        }    
     }
     
     fclose(fd);
     return 1;
  }  
/*-------------------------------------------------------------------------*/
  static int ReadRecover(pScanData self)
  {
     FILE *fd;
     struct RecoHead sHead;
     struct VarHead  sVar;
     pVarEntry       pVar;
     void            *pData;
     CountEntry      CountData;
     int i,iRet;
     
     assert(self);
     assert(self->pCon);
     
     fd = fopen(self->pRecover,"rb");
     if(!fd)
     {
       return 0;
     }
     
     /* read Header */
     iRet = fread(&sHead,sizeof(struct RecoHead),1,fd);
     if(iRet != 1)
     {
        SCWrite(self->pCon,"ERROR: Recover File corrupted",eError);
        fclose(fd);
        return 0;
     }
     self->iNP      = sHead.iNP;
     self->iMode    = sHead.iMode;
     self->fPreset  = sHead.fPreset;
     self->iCounts  = sHead.iCounts;
     self->iChannel = sHead.iChannel;
     
     /* read Scan Variables */
     self->iScanVar = 0;
     for(i = 0; i < sHead.iScanVar; i++)
     {
        iRet = fread(&sVar,sizeof(struct VarHead),1,fd);
        if(iRet != 1)
        {
           SCWrite(self->pCon,"ERROR: Recover File corrupted",eError);
           fclose(fd);
           return 0;
        }
        AddScanVar(self,self->pSics,self->pCon,
                   sVar.pName, sVar.fStart, sVar.fStep);
        DynarGet(self->pScanVar,i,&pData);
        pVar = (pVarEntry)pData;
        pVar->fData = (float *)malloc(sHead.iNP*sizeof(float));
        if(!pVar->fData)
        {
          SCWrite(self->pCon,"ERROR: out of memory in scan::ReadRecover",eError);
          fclose(fd);
          return 0;
        }           
        fread(pVar->fData,sizeof(float),sHead.iNP,fd);        
     }
     
     /* read counts */
     for(i = 0; i < sHead.iCounts; i++)
     {
       fread(&CountData,sizeof(CountEntry),1,fd);
       DynarPutCopy(self->pCounts,i,&CountData,sizeof(CountEntry));
     }
     
     fclose(fd);
     return 1;
  }  
/*--------------------------------------------------------------------------*/
  static int PrepareScan(pScanData self)
  {
     pVarEntry pVar = NULL;
     void *pDings;
     int i, iRet;
     float fVal;
     char pBueffel[512];
     char pMessage[1024];
     
     assert(self);
     assert(self->iNP > 0);
     assert(self->pCon);
     
     /* check boundaries of scan variables and allocate storage */
     for(i = 0; i < self->iScanVar; i++)
     {
       DynarGet(self->pScanVar,i,&pDings);
       pVar = (pVarEntry)pDings;
       if(pVar)
       {
          /* start value */
          fVal = pVar->fStart;
          iRet = pVar->pInter->CheckLimits(pVar->pObject,
                                         fVal,pBueffel,511);
          if(!iRet)
          {
             sprintf(pMessage,"ERROR: %s, scan aborted",pBueffel);
             SCWrite(self->pCon,pBueffel,eError);
             return 0;
          }           
          /* end value */
          fVal = pVar->fStart + self->iNP * pVar->fStep;                    
          iRet = pVar->pInter->CheckLimits(pVar->pObject,
                                         fVal,pBueffel,511);
          if(!iRet)
          {
             sprintf(pMessage,"ERROR: %s, scan aborted",pBueffel);
             SCWrite(self->pCon,pBueffel,eError);
             return 0;
          }         
          /* allocate data space */
          if(pVar->fData)
          {
            free(pVar->fData);
            pVar->fData = NULL;
          }  
          pVar->fData = (float *)malloc(self->iNP * sizeof(float));
          if(!pVar->fData)
          {
            SCWrite(self->pCon,"ERROR: out of memory in scan, aborting",eError);
            return 0;
          }
          memset(pVar->fData,0,self->iNP * sizeof(float));
       }
       else
       {
         SCWrite(self->pCon,
           "WARNING: Internal error, no scan variable, I try to continue",
           eWarning);
       }
       pVar = NULL;
     } /* end for */ 
     
     /* configure counter */
     SetCounterMode((pCounter)self->pCounterData,self->iMode);
     SetCounterPreset((pCounter)self->pCounterData, self->fPreset);
     self->iCounts = 0;
     
     return 1;
  }  
/*--------------------------------------------------------------------------*/
  static int StartToDrive(pScanData self, int iPoint)
  {
     pVarEntry pVar = NULL;
     void *pDings;
     int i, iRet, status;
     float fVal;
     pDummy pDum;
     char pBueffel[512];

     assert(self);
     assert(self->pCon);
     
 
     /* loop over all scan variables */
     status = 1;
     for(i = 0; i < self->iScanVar; i++)
     {
        DynarGet(self->pScanVar,i,&pDings);
        pVar = (pVarEntry)pDings;
        if(pVar)
        {
           pDum = (pDummy)pVar->pObject;
           fVal = pVar->fStart + iPoint * pVar->fStep;
           iRet = StartDevice(pServ->pExecutor, 
                              pVar->Name,
                              pDum->pDescriptor,
                              pVar->pObject,
                              self->pCon,
                              fVal); 
           if(!iRet)
           {
             sprintf(pBueffel,"ERROR: Failed to start %s",pVar->Name);
             SCWrite(self->pCon,pBueffel,eError);
             status = 0;
             break;
           }                                                    
        }
     }
     return status;
  }  
/*---------------------------------------------------------------------------*/
  static int CollectScanData(pScanData self, int iPoint)
  {
     pVarEntry pVar = NULL;
     void *pDings;
     int i, iRet, status;
     float fVal;
     char pStatus[512], pItem[20];
     char pHead[512];
     CountEntry sCount;
     char *pAns = NULL, *pPtr = NULL ;
     Tcl_Interp *pTcl;

     assert(self);
     assert(self->pCon);
     
     /* prepare output header */
     sprintf(pHead,"%-5.5s","NP");
     sprintf(pStatus,"%-5d",iPoint);
 
     /* loop over all scan variables */
     status = 1;
     for(i = 0; i < self->iScanVar; i++)
     {
        DynarGet(self->pScanVar,i,&pDings);
        pVar = (pVarEntry)pDings;
        if(pVar)
        {
           fVal = pVar->pInter->GetValue(pVar->pObject,self->pCon);
           pVar->fData[iPoint] = fVal;
           sprintf(pItem,"%-10.10s",pVar->Name);
           strcat(pHead,pItem);
           sprintf(pItem,"%-10.3f",fVal);
           strcat(pStatus,pItem);
        }
     }
  
     /* store counter data */
     /* monitors */
     for(i = 1; i < 10; i++)
     {
        sCount.Monitors[i-1] = GetMonitor((pCounter)self->pCounterData,i,
                                        self->pCon);
     }
     if( self->iChannel != 0 && self->iChannel != -10 )
     {
       sCount.Monitors[self->iChannel - 1] = 
           GetCounts((pCounter)self->pCounterData,
                                                   self->pCon);     
     }
     /* counts, depending on iChannel */
     strcat(pHead,"Counts         ");
     if(self->iChannel == -10)
     { 
       /* execute the Tcl-script for getting the data */
       pTcl = (Tcl_Interp *)self->pSics->pTcl;
       if(!self->pCommand)
       {
         SCWrite(self->pCon,
          "ERROR: command must be configured for user defined scans",
          eError);
         SCSetInterrupt(self->pCon,eAbortBatch);
         return 0;
       }
       iRet = Tcl_Eval(pTcl,self->pCommand);
       if(iRet != TCL_OK)
       {
           SCWrite(self->pCon,pTcl->result,eError);
           return 0;
       } 
       /* interprete the Tcl result as a list of counts 
          WARNING: this may need to be changed when switching to
          future versions of Tcl
       */
       pAns = strdup(pTcl->result);
       pPtr = strtok(pAns," ");
       if(!pPtr)
       {
         SCWrite(self->pCon,"ERROR: no counts found in Tcl-result",eError);
         return 0;
       }          
       sscanf(pPtr,"%f",&fVal);
       sCount.lCount = (long)fVal;
       i = 0;
       while( (pPtr != NULL) && (i < 10))
       {
          pPtr = strtok(NULL," ");
          if(pPtr)
	  {
             sscanf(pPtr,"%f",&fVal);
             sCount.Monitors[i] = (long)fVal;
             i++;
          }
       }     
       free(pAns);
     }
     else if(self->iChannel == 0)
     {
        sCount.lCount = GetCounts((pCounter)self->pCounterData,self->pCon);
     }
     else
     {
        sCount.lCount = GetMonitor((pCounter)self->pCounterData,
                                  self->iChannel, self->pCon);
     }
     sprintf(pItem,"%-15d",sCount.lCount);
     strcat(pStatus,pItem);

     /* get time */
     sCount.fTime = GetCountTime((pCounter)self->pCounterData,
                                 self->pCon);
     strcat(pHead,"Monitor1    ");
     sprintf(pItem,"%-12d",sCount.Monitors[0]);
     strcat(pStatus,pItem);
     strcat(pHead,"Monitor2    ");
     sprintf(pItem,"%-12d",sCount.Monitors[1]);
     strcat(pStatus,pItem);
     strcat(pHead,"Monitor3    ");
     sprintf(pItem,"%-12d",sCount.Monitors[2]);
     strcat(pStatus,pItem);
     strcat(pHead,"Time  ");
     sprintf(pItem,"%-6.1f",sCount.fTime);
     strcat(pStatus,pItem);
     

     /* write progress */
     strcat(pHead,"\n");
     strcat(pStatus,"\n");
     SCWrite(self->pCon,pHead,eWarning);
     SCWrite(self->pCon,pStatus,eWarning);
     
     /* stow away */
     DynarReplace(self->pCounts,self->iCounts,&sCount,sizeof(CountEntry));
     self->iCounts++;
     return 1;
  }  
/*------------------------------------------------------------------------*/
  static int ScanDrive(pScanData self, int iPoint)
  {
    int iRet;
    long lTask;
    int status;

    iRet = StartToDrive(self,iPoint);
    if(!iRet)
    {
	SCWrite(self->pCon,"ERROR: Cannot Drive, Scan aborted",eError);
	status = 0;
    }
    else
    {
      status = 1;
    }
    /* wait for finish */
    lTask = GetDevexecID(pServ->pExecutor);
    if(lTask > 0)
    {
      TaskWait(pServ->pTasker,lTask);
    }
    return status;
  }
/*--------------------------------------------------------------------------*/
  static int ScanCount(pScanData self, int iPoint)
  {
    pDummy pDum;
    int iRet;
    long lTask;

    pDum = (pDummy)self->pCounterData;
    iRet = StartDevice(pServ->pExecutor,
		       "ScanCounter",
		       pDum->pDescriptor,
		       self->pCounterData,
		       self->pCon,
		       self->fPreset);
    if(!iRet)
    {
	SCWrite(self->pCon,"ERROR: Cannot Count, Scan aborted",eError);
	return 0;
    }
    SetStatus(eCounting);
    /* wait for finish */
    lTask = GetDevexecID(pServ->pExecutor);
    if(lTask > 0);
    {
      TaskWait(pServ->pTasker,lTask);
    }
    return 1;
  }
/*---------------------------------------------------------------------------*/
  static int ScanLoop(pScanData self)
  {
      int i,iInt,iRet,iStatus;
      
      assert(self);
      assert(self->pCon);
      
      InvokeCallBack(self->pCall,SCANSTART,self);
      for(i = self->iCounts; i < self->iNP; i++)
      {
/*--------- drive */
         iRet = self->ScanDrive(self,i);
         if(!iRet)
	 {
           return 0;
         }
         /* finished, check for interrupts. Whatever happened, user 
            interrupt or HW interrupt, it will be on our connection
         */
         iInt = SCGetInterrupt(self->pCon);
         switch(iInt)
         {
           case eContinue:
                         break;
           case eAbortOperation:
                         continue;
                         break;
           case eAbortScan:
                         SCWrite(self->pCon,"ERROR: Scan aborted",eError);
                         /* eat the interrupt, the requested op has been
                            done
                         */   
                         SCSetInterrupt(self->pCon,eContinue);
                         return 0;
                         break;
           default: /* all others */
                         SCWrite(self->pCon,"ERROR: Scan aborted",eError);
                         return 0;
                         break; 
         }   
/*-------------- count */
         iRet = self->ScanCount(self, i);
         if(!iRet)
	 {
            return 0;
         }
         
         /* finished, check for interrupts. Whatever happened, user 
            interrupt or HW interrupt, it will be on our connection
         */
         iInt = SCGetInterrupt(self->pCon);
         switch(iInt)
         {
           case eContinue:
                         break;
           case eAbortOperation:
                         continue;
                         break;
           case eAbortScan:
                         SCWrite(self->pCon,"ERROR: Scan aborted",eError);
                         /* eat the interrupt, the requested op has been
                            done
                         */   
                         SCSetInterrupt(self->pCon,eContinue);
                         return 0;
                         break;
           default: /* all others */
                         SCWrite(self->pCon,"ERROR: Scan aborted",eError);
                         return 0;
                         break; 
         }   
/*-------- scan post processing */
         self->CollectScanData(self,i);
         InvokeCallBack(self->pCall,SCANPOINT,self);
         self->WriteScanPoints(self,i);
         if(self->pRecover)
         {
                WriteRecover(self);            
         }  
      }
      
      return 1;
  }
/*--------------------------------------------------------------------------*/
  int DoScan(pScanData self, int iNP, int iMode, float fPreset,
             SicsInterp *pSics, SConnection *pCon)
  {
       int iRet;
       char *pPtr = NULL;
       char pBueffel[1024];
       
       assert(self);
       assert(pCon);
       assert(pSics);
       
       self->pCon = pCon;
       self->pSics = pSics;
       
       /* check arguments */
       if(iNP <= 0)
       {
          SCWrite(self->pCon,"ERROR: iNP < 0, nothing to do, Scan aborted",eError);
          self->pCon = NULL;
          self->pSics = NULL;
          return 0;
       }
       if(self->iScanVar <= 0)
       {
         SCWrite(self->pCon,"WARNING: no scan variables given",eWarning);
       }
       
       if( (iMode != eTimer) && (iMode != ePreset))
       {
          SCWrite(self->pCon,"ERROR: Invalid counter mode given",eError);
          self->pCon = NULL;
          self->pSics = NULL;
          return 0;    
       }
       self->iNP = iNP;
       self->iMode = iMode;
       self->fPreset = fPreset;
       
       /* do some preprocessing */
       iRet =  PrepareScan(self);
       if(!iRet)
       {
         self->pCon = NULL;
         self->pSics = NULL;
         return 0;
       }
       
       /* allocate a new data file */
       pPtr = ScanMakeFileName(self->pSics,self->pCon,self->ext);
       if(!pPtr)
       {
          SCWrite(self->pCon,"ERROR: cannot allocate new data filename, Scan aborted",
                  eError);
          self->pCon = NULL;
          self->pSics = NULL;
          return 0;
       }
       sprintf(pBueffel,"Writing data file: %s ...",pPtr);
       SCWrite(self->pCon,pBueffel,eWarning);
       strcpy(self->pFile,pPtr);
       free(pPtr);
       iRet = self->WriteHeader(self);
       if(!iRet)
       {
          SCWrite(self->pCon,"ERROR: cannot open data file, Scan aborted",
                  eError);
          self->pCon = NULL;
          self->pSics = NULL;
          return 0;
       }

       self->iActive = 1;
       iRet = ScanLoop(self);
       InvokeCallBack(self->pCall,SCANEND,self);
       SendQuieck(QUIECK,self->pFile);
       self->iActive = 0;
       self->pCon = NULL;
       self->pSics = NULL;
       return iRet;         
  }   
/*----------------------------------------------------------------------------
   SilentScan does a scan which does not produce a data file. It is intended
   for internal use. Only status messages appear on screen.
---------------------------------------------------------------------------*/    
  int SilentScan(pScanData self, int iNP, int iMode, float fPreset,
             SicsInterp *pSics, SConnection *pCon)
  {
       int iRet;
       char *pPtr = NULL;
       char pBueffel[1024];
       int (*HeaderFunc)(pScanData self), (*ScanFunc)(pScanData self,
                                                      int iPoint);
       
       assert(self);
       assert(pCon);
       assert(pSics);
       
       /* check arguments */
       if(iNP <= 0)
       {
          SCWrite(self->pCon,"ERROR: iNP < 0, nothing to do, Scan aborted",eError);
          return 0;
       }
       if(self->iScanVar <= 0)
       {
         SCWrite(self->pCon,"WARNING: no scan variables given",eWarning);
       }
       
       if( (iMode != eTimer) && (iMode != ePreset))
       {
          SCWrite(self->pCon,"ERROR: Invalid counter mode given",eError);
          return 0;    
       }

       HeaderFunc = self->WriteHeader;
       self->WriteHeader = DummyWrite;
       ScanFunc = self->WriteScanPoints;
       self->WriteScanPoints = DummyWrite2; 
       self->pCon = pCon;
       self->pSics = pSics;
       self->iNP = iNP;
       self->iMode = iMode;
       self->fPreset = fPreset;
       
       /* do some preprocessing */
       iRet =  PrepareScan(self);
       if(!iRet)
       {
         self->WriteHeader = HeaderFunc;
         self->WriteScanPoints = ScanFunc;
         self->pCon = NULL;
         self->pSics = NULL;
         return 0;
       }
       
       self->iActive = 1;
       iRet = ScanLoop(self);
       self->iActive = 0;
       self->pCon = NULL;
       self->pSics = NULL;
       self->WriteHeader = HeaderFunc;
       self->WriteScanPoints = ScanFunc;
       
       return iRet;         
  }   
/*--------------------------------------------------------------------------*/
  int RecoverScan(pScanData self, SicsInterp *pSics, SConnection *pCon)
  {
    int iRet;
    char *pPtr = NULL, pBueffel[512];
    
    assert(pSics);
    assert(pCon);
    
    self->pCon = pCon;
    self->pSics = pSics;
    
    /* read recover file */
    iRet = ReadRecover(self);
    if(!iRet)
    {
      return iRet;
    }
    
    /* configure counter */
     SetCounterMode((pCounter)self->pCounterData,self->iMode);
     SetCounterPreset((pCounter)self->pCounterData, self->fPreset);
    

     /* new scan data file */
      pPtr = ScanMakeFileName(self->pSics,self->pCon,self->ext);
       if(!pPtr)
       {
          SCWrite(self->pCon,"ERROR: cannot allocate new data filename, Scan aborted",
                  eError);
          self->pCon = NULL;
          self->pSics = NULL;
          return 0;
       }
       sprintf(pBueffel,"Writing data file: %s ...",pPtr);
       SCWrite(self->pCon,pBueffel,eWarning);
       strcpy(self->pFile,pPtr);
       free(pPtr);
       iRet = self->WriteHeader(self);
       if(!iRet)
       {
          SCWrite(self->pCon,"ERROR: cannot open data file, Scan aborted",
                  eError);
          self->pCon = NULL;
          self->pSics = NULL;
          return 0;
       }

       self->iActive = 1;
       iRet = ScanLoop(self);
       InvokeCallBack(self->pCall,SCANEND,self);
       SendQuieck(QUIECK,self->pFile);
       self->iActive = 0;
       self->pCon = NULL;
       self->pSics = NULL;
       return iRet;         
        
  }   
/*--------------------------------------------------------------------------*/
  int GetScanNP(pScanData self)
  {
    assert(self);
    return self->iNP;
  }  
/*--------------------------------------------------------------------------*/
  float GetScanPreset(pScanData self)
  {
    assert(self);
    return self->fPreset;
  }  
/*--------------------------------------------------------------------------*/
  int GetScanCounts(pScanData self,long *lData, int iDataLen)
  {
     int i, iEnd;
     pCountEntry pData = NULL;
     void *pPtr = NULL;
     
     assert(self);
     /* hanlde iEnd */
     if(self->iCounts < iDataLen)
     {
       iEnd = self->iCounts;
     }
     else
     {
       iEnd = iDataLen;
     }
     
     /* initialise to 0 */
     memset(lData,0,iDataLen*sizeof(long));
     
     /* the loop */
     for(i = 0; i < iEnd; i++)
     {
       DynarGet(self->pCounts,i,&pPtr);
       pData = (pCountEntry)pPtr;
       if(pData)
       {
         lData[i] = pData->lCount;
       }       
       pData = NULL;
     }
     
     return 1;
  }  
/*--------------------------------------------------------------------------*/  
  int GetScanMonitor(pScanData self,int iWhich,long *lData, int iDataLen)
  {
     int i, iEnd;
     pCountEntry pData = NULL;
     void *pPtr = NULL;
     
     assert(self);

     /* hanlde iEnd */
     if(self->iCounts < iDataLen)
     {
       iEnd = self->iCounts;
     }
     else
     {
       iEnd = iDataLen;
     }
     
     /* initialise to 0 */
     memset(lData,0,iDataLen*sizeof(long));
     
     /* the loop */
     for(i = 0; i < iEnd; i++)
     {
       DynarGet(self->pCounts,i,&pPtr);
       pData = (pCountEntry)pPtr;
       if(pData)
       {
         lData[i] = pData->Monitors[iWhich];
       }       
       pData = NULL;
     }
     
     return 1;
  }  
/*--------------------------------------------------------------------------*/
  int GetScanVar(pScanData self, int iWhich, float *fData, int iDataLen)
  {
    int iEnd, i;
    pVarEntry pVar = NULL;
    void *pPtr = NULL;
    
    /* does it exist ?*/
    if( (iWhich < 0) || (iWhich >= self->iScanVar) )
    {
      return 0;
    }

     /* handle iEnd */
     if(self->iCounts < iDataLen)
     {
       iEnd = self->iCounts;
     }
     else
     {
       iEnd = iDataLen;
     }

     DynarGet(self->pScanVar,iWhich,&pPtr);
     pVar = (pVarEntry)pPtr;
     if(pVar)
     {     
       /* initialise to theoretical values */
       for(i = 0; i < self->iNP; i++)
       {     
         fData[i] = pVar->fStart + i * pVar->fStep;       
       }

       /* copy the actual scan data */
       memcpy(fData,pVar->fData,iEnd*sizeof(float));
       return 1;
     }
     else
     {
       return 0;
     }
     
     /* not reached */
     assert(0);
  }  
/*-------------------------------------------------------------------------*/
  int GetScanVarName(pScanData self, int iWhich, char *pName, int iLength)
  {
    pVarEntry pVar = NULL;
    void *pPtr = NULL;
    
    /* does it exist ?*/
    if( (iWhich < 0) || (iWhich >= self->iScanVar) )
    {
      return 0;
    }

     /* get the scan var */
     DynarGet(self->pScanVar,iWhich,&pPtr);
     pVar = (pVarEntry)pPtr;
     if(pVar)
     {
       strncpy(pName,pVar->Name,iLength);
       return 1;
     }
     else
     {
       return 0;
     }
  }  
/*-------------------------------------------------------------------------*/
  int GetScanVarStep(pScanData self, int iWhich, float *fStep)
  {
    pVarEntry pVar = NULL;
    void *pPtr = NULL;
    
    /* does it exist ?*/
    if( (iWhich < 0) || (iWhich >= self->iScanVar) )
    {
      return 0;
    }

     /* get the scan var */
     DynarGet(self->pScanVar,iWhich,&pPtr);
     pVar = (pVarEntry)pPtr;
     if(pVar)
     {
       *fStep = pVar->fStep;
       return 1;
     }
     else
     {
       return 0;
     }
  }  
/*--------------------------------------------------------------------------
  ScanIntegrate does an integration of the current scan data. It returns 1 on
  success or one of the integrate error codes defined in integrate.h
-----------------------------------------------------------------------------*/
  int ScanIntegrate(pScanData self, float *fSum, float *fVar)
  {
     long *lData = NULL;
     int iRet;
     
     assert(self);
      
     /* no integration if no peak measured */ 
     if(self->iCounts <= self->iWindow*2)
                return INTEGNOPEAK;  
     
     /* get some memory */
     lData = (long *)malloc(self->iNP*sizeof(long));
     if(!lData)
     {
         return INTEGNOPEAK;
     }
     /* get counts */
     GetScanCounts(self,lData,self->iNP);
     /* Do it */
     iRet = GabePeakIntegrate(self->iWindow,self->iNP,lData, fSum, fVar);
     free(lData);
     return iRet;
  }    
/*--------------------------------------------------------------------------
  SimScan is a debugging aid for other modules. It simulates a scan on a
  variable in the range from 10 -20 degrees in angle and 100 points. Data 
  is created as a Gauss function located at fPos, with a halfwidth of
  FWHM and a height of fHeight. All data is randomized a little in a range
  of 5 counts. The peak will sit on a background of 20 counts. This requires
  a motor a4 to exist as it will be used for x-axis simulation. This routine
  will not stop you from simulating shit if you throw shit at it!
----------------------------------------------------------------------------*/   
  int SimScan(pScanData self, float fPos, float FWHM, float fHeight)
  {
        int i, iRet;
        SConnection *pCon = NULL;
        CountEntry sCount;
        pVarEntry pVar = NULL;
        void *pDings = NULL;
        float x, y, fTmp, fStdDev;
        
        
        assert(self);
        
        /* go to a clean state */
        ClearScanVar(self);
       
        /* put in the scan variable */
        pCon = SCCreateDummyConnection(pServ->pSics);
        if(!pCon)
        {
          return 0;
        }
        iRet = AddScanVar(self,pServ->pSics,pCon,"a4",10., 0.1);
        SCDeleteConnection(pCon);
        if(!iRet)
        {
          return 0;
        }
        
        /* do the x-axis of the scan */
        DynarGet(self->pScanVar,0,&pDings);
        pVar = (pVarEntry)pDings;
        if(!pVar)
        {
          return 0;
        }
        pVar->fData = (float *)malloc(90*sizeof(float));
        if(!pVar->fData)
        {
          return 0;
        }
        
        
        /* create scan data in loop */
        fStdDev = FWHM/2.354;
        for(i = 0; i < 90; i++)
        {
           x = pVar->fData[i] = 10. + 0.1 * i;
           sCount.i = i;
           /* gaussian */
           fTmp = (x - fPos)/fStdDev;
           y = fHeight*0.4* exp(-0.5*fTmp*fTmp);
           /* randomize a little */
           y += 7. * (float)rand()/(float)RAND_MAX;
           /* add a little background */
           sCount.lCount = (long)(10 + y);
           /* stow away */
           DynarReplace(self->pCounts,i,&sCount,sizeof(CountEntry));
        }
        self->iCounts = 90;
        self->iNP = 90;
        return 1;
  }  
/*---------------------------------------------------------------------------*/
  int ScanFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
                  int argc, char *argv[])
  {
        pScanData pNew = NULL;
        pCounter pCount = NULL;
        pDummy pDum = NULL;
        CommandList *pCom = NULL;
        char pBueffel[512];
        int iRet;
        
        if(argc < 5)
        {
          SCWrite(pCon,"ERROR: Insufficient number of arguments to ScanFactory",
                  eError);
          return 0;         
        }
        
        strtolower(argv[1]);
        strtolower(argv[2]);
        pCom = FindCommand(pSics,argv[2]);
        if(!pCom)
        {
          sprintf(pBueffel,"ERROR: cannot find counter %s",argv[2]);
          SCWrite(pCon,pBueffel,eError);
          return 0;
        }
        pDum = (pDummy)pCom->pData;
        if(!pDum)
        {
          sprintf(pBueffel,"ERROR: counter %s has no data",argv[2]);
          SCWrite(pCon,pBueffel,eError);
          return 0;
        }
        if(!(pDum->pDescriptor->GetInterface(pDum,COUNTID)))
        {
          sprintf(pBueffel,"ERROR: object %s is NO counter",argv[2]);
          SCWrite(pCon,pBueffel,eError);
          return 0;
        }
        pNew = CreateScanObject(argv[4],argv[3],(pCounter)pCom->pData);
        if(!pNew)
        {
          SCWrite(pCon,"ERROR: failure to allocate scan data structure",
                  eError);
          return 0;         
        }
        
        iRet = AddCommand(pSics,
                          argv[1],
                          ScanWrapper,
                          DeleteScanObject,
                          pNew);
        if(!iRet)
        {
          sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[1]);
          SCWrite(pCon,pBueffel,eError);
          return 0;
        }
        return 1;                  
  }          
/*--------------------------------------------------------------------------*/
  static int ScanInterest(int iEvent, void *pEventData, void *pUser)
  {
      pScanData self = NULL;
      SConnection *pCon = NULL;
      char *pPtr = NULL, pItem[20];
      long *lData = NULL;
      int i;
      
      self = (pScanData)pEventData;
      pCon = (SConnection *)pUser;
      
      assert(self);
      assert(pCon);
      
      if(iEvent == SCANSTART)
      {
        SCWrite(pCon,"NewScan",eWarning);
        return 1;
      }
      else if(iEvent == SCANEND)
      {
        SCWrite(pCon,"ScanEnd",eWarning);
        return 1;
      }
      else if(iEvent == SCANPOINT)
      {
        /* allocate space */
        pPtr = (char *)malloc((self->iNP*20+20)*sizeof(char));
        if(!pPtr)
        {
          return 0;
        }
        memset(pPtr,0,(self->iNP*20+20)*sizeof(char));
        lData = (long *)malloc(self->iNP*sizeof(long));
        if(!lData)
        {
          return 0;
        }
        memset(lData,0,self->iNP*sizeof(long));
        
        /* get counts */
        GetScanCounts(self,lData,self->iNP);
        /* format a message */
        strcpy(pPtr,"scan.Counts= ");
        for(i = 0; i < self->iNP; i++)
        {
          sprintf(pItem,"{%d} ",lData[i]);
          strcat(pPtr,pItem);
        }
        SCWrite(pCon,pPtr,eWarning);
        free(lData);
        free(pPtr);
        return 1;
      }
      return 1;
  }           
/*--------------------------------------------------------------------------*/
  static int ScanUUInterest(int iEvent, void *pEventData, void *pUser)
  {
      pScanData self = NULL;
      SConnection *pCon = NULL;
      char pItem[20];
      long *lData = NULL;
      int *iData  = NULL;
      int i;
      
      self = (pScanData)pEventData;
      pCon = (SConnection *)pUser;
      
      assert(self);
      assert(pCon);
      
      if(iEvent == SCANSTART)
      {
        SCWrite(pCon,"NewScan",eWarning);
        return 1;
      }
      else if(iEvent == SCANEND)
      {
        SCWrite(pCon,"ScanEnd",eWarning);
        return 1;
      }
      else if(iEvent == SCANPOINT)
      {
        /* allocate space */
        lData = (long *)malloc(self->iNP*sizeof(long));
        iData = (int *)malloc(self->iNP*sizeof(int));
        if(!lData || !iData)
        {
          return 0;
        }
        memset(lData,0,self->iNP*sizeof(long));
        memset(iData,0,self->iNP*sizeof(int));
        
        /* get counts */
        GetScanCounts(self,lData,self->iNP);
        /* put into network byte order */
        for(i = 0; i < self->iNP; i++)
        {
          iData[i] = htonl((int)lData[i]);
        }
        SCWriteUUencoded(pCon,"ScanData",iData,self->iNP*sizeof(int));
        free(lData);
        free(iData);
        return 1;
      }
      return 1;
  }           
/*---------------------------------------------------------------------------*/
  int ScanWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
                  int argc, char *argv[])
  {
        pScanData self = NULL;
        char pBueffel[512];
        double fStep, fStart, fPreset;
        float *fData = NULL;
        int lNP;
        int iChannel;
        int iRet, iMode,i;
        char *pPtr = NULL, pItem[20];
        long *lData = NULL, lID;
        int *iData;
        void *pVarData = NULL;
        pVarEntry pVar = NULL;
        float fSum, fVar;
        double x;
        float fPos, FWHM, fHeight;
        
        self = (pScanData)pData;
        assert(self);
        
        argtolower(argc,argv);
        if(argc < 2)
        {
          sprintf(pBueffel,"ERROR: not enough arguments for %s",argv[0]);
          SCWrite(pCon,pBueffel,eError);
          return 0;
        }
        
/*------------ first interpret commands which do not require user rights */
/*---------- getfile */
        if(strcmp(argv[1],"getfile") == 0)
        {
           sprintf(pBueffel,"scan.File = %s",self->pFile);
           SCWrite(pCon,pBueffel,eValue);
           return 1;
        }        
/*--------- getcounts */
        else if(strcmp(argv[1],"getcounts") == 0)
        {
          /* get some memory */
          if(self->iNP < 1)
          {
            SCWrite(pCon,"ERROR: no counts available",eError);
            return 0;
          }
          lData = (long *)malloc(self->iNP*sizeof(long));
          if(!lData)
          {
            SCWrite(pCon,"ERROR: out of memory in scan",eError);
            return 0;
          }
          pPtr = (char *)malloc((self->iNP*20+20)*sizeof(char));
          if(!pPtr)
          {
            SCWrite(pCon,"ERROR: out of memory in scan",eError);
            return 0;
          }
          memset(pPtr,0,(self->iNP*20+20)*sizeof(char));
          
          /* get counts */
          GetScanCounts(self,lData,self->iNP);
          
          /* format them */
          strcpy(pPtr,"scan.Counts= ");
          for(i = 0; i < self->iNP; i++)
          {
            sprintf(pItem,"{%d} ",lData[i]);
            strcat(pPtr,pItem);
          }
          SCWrite(pCon,pPtr,eValue);
          free(lData);
          free(pPtr);
          return 1;
        }       
/*---------- uucounts */
        else if(strcmp(argv[1],"uucounts") == 0)
        {
          /* get some memory */
          if(self->iNP < 1)
          {
            SCWrite(pCon,"ERROR: no counts available",eError);
            return 0;
          }
          lData = (long *)malloc(self->iNP*sizeof(long));
          iData = (int *)malloc((self->iNP + 1)*sizeof(int));
          if(!lData || !iData )
          {
            SCWrite(pCon,"ERROR: out of memory in scan",eError);
            return 0;
          }
          
          /* get counts */
          GetScanCounts(self,lData,self->iNP);
          /* copy them */
          memset(iData,0,self->iNP+1);
          iData[0] = self->iNP;
          for(i = 0; i < self->iNP; i++)
          {
            iData[i+1] = htonl(lData[i]);
          }
          SCWriteUUencoded(pCon,"ScanCounts",iData,
                           (self->iNP + 1)*sizeof(int));
          return 1;                 
        }        
/*--------- getvardata */
        else if(strcmp(argv[1],"getvardata") == 0)
        {
          /* we need an integer parameter saying which */
          if(argc >= 3)
          {
            iRet = Tcl_GetInt(pSics->pTcl,argv[2],&i);
            if(iRet != TCL_OK)
            {
              sprintf(pBueffel,"ERROR: expected integer, got %s",argv[2]);
              SCWrite(pCon,pBueffel,eError);
              return 0;
            }
          }  
          else
          {
              SCWrite(pCon,"ERROR: expected number of variable to retrieve data for ",
                      eError);
              return 0;        
          }
          /* check the int for validity */
          if( (i < 0) || (i >= self->iScanVar))
          {
            SCWrite(pCon,"ERROR: non existent scan variable requested!",eError);
            return 0;
          }
        
          /* get some memory */
          fData = (float *)malloc(self->iNP*sizeof(float));
          if(!fData)
          {
            SCWrite(pCon,"ERROR: out of memory in scan",eError);
            return 0;
          }
          pPtr = (char *)malloc((self->iNP*20+20)*sizeof(char));
          if(!pPtr)
          {
            SCWrite(pCon,"ERROR: out of memory in scan",eError);
            return 0;
          }
          memset(pPtr,0,(self->iNP*20+20)*sizeof(char));
          
          /* get data */
          GetScanVar(self,i,fData,self->iNP);
          
          /* get name of ScanVar */
          DynarGet(self->pScanVar,i,&pVarData);
          pVar = (pVarEntry)pVarData;
          if(!pVar)
          {
            SCWrite(pCon,"ERROR: Corrupted data structures, inform Programmer",
                    eError);
            return 0;        
          }
          
          /* format them */
          sprintf(pPtr,"scan.%s = ", pVar->Name);
          for(i = 0; i < self->iNP; i++)
          {
            sprintf(pItem,"{%12.3f} ",fData[i]);
            strcat(pPtr,pItem);
          }
          SCWrite(pCon,pPtr,eValue);
          free(fData);
          free(pPtr);
          return 1;
        }       
/*-------- interest */
        else if(strcmp(argv[1],"interest") == 0)
        {
           lID = RegisterCallback(self->pCall, SCANSTART, ScanInterest,
                                  pCon, NULL);
           SCRegister(pCon,pSics, self->pCall,lID);
           lID = RegisterCallback(self->pCall, SCANEND, ScanInterest,
                                  pCon, NULL);
           SCRegister(pCon,pSics, self->pCall,lID);
           lID = RegisterCallback(self->pCall, SCANPOINT, ScanInterest,
                                  pCon, NULL);
           SCRegister(pCon,pSics, self->pCall,lID);
           SCSendOK(pCon);
           return 1;
        }
/*-------- uuinterest */
        else if(strcmp(argv[1],"uuinterest") == 0)
        {
           lID = RegisterCallback(self->pCall, SCANSTART, ScanUUInterest,
                                  pCon, NULL);
           SCRegister(pCon,pSics, self->pCall,lID);
           lID = RegisterCallback(self->pCall, SCANEND, ScanUUInterest,
                                  pCon, NULL);
           SCRegister(pCon,pSics, self->pCall,lID);
           lID = RegisterCallback(self->pCall, SCANPOINT, ScanUUInterest,
                                  pCon, NULL);
           SCRegister(pCon,pSics, self->pCall,lID);
           SCSendOK(pCon);
           return 1;
        }
/* ------- uninterest */
        else if(strcmp(argv[1],"uninterest") == 0)
        {
           RemoveCallback2(self->pCall,pCon);
           SCUnregister(pCon,self->pCall);
           SCSendOK(pCon);
           return 1;
        }               

/*------- deal with command needing user rights in all cases */   
        
        /* check User Rights */
        if(!(SCMatchRights(pCon,usUser)))
        {
          SCWrite(pCon,"ERROR: You are NOT authorised to use scan",eError);
          return 0;
        }
/*---------- add command */
        if(strcmp(argv[1],"add") == 0)
        {
           if(argc < 5)
           {
             sprintf(pBueffel,"ERROR: Insufficient number of arguments given for %s add",
                     argv[0]);
             SCWrite(pCon,pBueffel,eError);
             return 0;        
           }
           /* get  numbers */
           iRet = Tcl_GetDouble(pSics->pTcl,argv[3],&fStart);
           if(iRet != TCL_OK)
           {
             sprintf(pBueffel,"ERROR: expected number, got %s",argv[3]);
             SCWrite(pCon,pBueffel,eError);
             return 0;        
           }
           iRet = Tcl_GetDouble(pSics->pTcl,argv[4],&fStep);
           if(iRet != TCL_OK)
           {
             sprintf(pBueffel,"ERROR: expected number, got %s",argv[3]);
             SCWrite(pCon,pBueffel,eError);
             return 0;        
           }
           iRet = AddScanVar(self,pSics,pCon,argv[2],(float)fStart,(float)fStep);
           if(iRet)
           {
             SCSendOK(pCon);
           }
           return iRet;  
        }
/* --------clear */
        else if(strcmp(argv[1],"clear") == 0)
        {
          iRet = ClearScanVar(self);
          if(iRet)
          {
             SCSendOK(pCon);
          }
          else
          {
            SCWrite(pCon,"ERROR: cannot change parameters while scanning",
                    eError);
            return 0;        
          }   
          return 1;
        }          
/*------------ configure */
        else if(strcmp(argv[1],"configure") == 0)
	{
	  /* managers only */ 
           if(!SCMatchRights(pCon,usMugger))
                    return 0;
           if(argc < 3)
	   {
             SCWrite(pCon,"ERROR: missing configure option",eError);
             return 0;
           }
           strtolower(argv[2]);
           if(strcmp(argv[2],"standard") == 0)
	   {
               ResetScanFunctions(self);
               SCSendOK(pCon);
               return 1;
           }
           else if(strcmp(argv[2],"amor") == 0)
           {
               ConfigureAmor(self);
               SCSendOK(pCon);
               return 1;
           }
           else
           {
              sprintf(pBueffel,"ERROR: option %s not recognized by configure",
                      argv[2]);
              SCWrite(pCon,pBueffel,eError);
              return 0;
           }
        }
/*---------- scan */
        else if(strcmp(argv[1],"run") == 0)
        {
          /* get NP */
           iRet = Tcl_GetInt(pSics->pTcl,argv[2],&lNP);
           if(iRet != TCL_OK)
           {
             sprintf(pBueffel,"ERROR: expected number, got %s",argv[3]);
             SCWrite(pCon,pBueffel,eError);
             return 0;        
           }
           /* interpret Mode */
           if(strcmp(argv[3],"timer") == 0)
           {
             iMode = eTimer;
           }
           else if(strcmp(argv[3],"monitor") == 0)
           {
             iMode = ePreset;
           }
           else
           {
             sprintf(pBueffel,"ERROR: %s not recognized as valid counter mode",
                     argv[3]);
             SCWrite(pCon,pBueffel,eError);
             return 0;         
           }
           /* preset */
           iRet = Tcl_GetDouble(pSics->pTcl,argv[4],&fPreset);
           if(iRet != TCL_OK)
           {
             sprintf(pBueffel,"ERROR: expected number, got %s",argv[3]);
             SCWrite(pCon,pBueffel,eError);
             return 0;        
           }
           iRet = DoScan(self,(int)lNP,iMode,(float)fPreset,
                         pSics,pCon);
           if(iRet)
           {
             SCSendOK(pCon);
           }     
           return iRet;
        }       
/*---------- silent */
        else if(strcmp(argv[1],"silent") == 0)
        {
          /* get NP */
           iRet = Tcl_GetInt(pSics->pTcl,argv[2],&lNP);
           if(iRet != TCL_OK)
           {
             sprintf(pBueffel,"ERROR: expected number, got %s",argv[3]);
             SCWrite(pCon,pBueffel,eError);
             return 0;        
           }
           /* interpret Mode */
           if(strcmp(argv[3],"timer") == 0)
           {
             iMode = eTimer;
           }
           else if(strcmp(argv[3],"monitor") == 0)
           {
             iMode = ePreset;
           }
           else
           {
             sprintf(pBueffel,"ERROR: %s not recognized as valid counter mode",
                     argv[3]);
             SCWrite(pCon,pBueffel,eError);
             return 0;         
           }
           /* preset */
           iRet = Tcl_GetDouble(pSics->pTcl,argv[4],&fPreset);
           if(iRet != TCL_OK)
           {
             sprintf(pBueffel,"ERROR: expected number, got %s",argv[3]);
             SCWrite(pCon,pBueffel,eError);
             return 0;        
           }
           iRet = SilentScan(self,(int)lNP,iMode,(float)fPreset,
                         pSics,pCon);
           if(iRet)
           {
             SCSendOK(pCon);
           }     
           return iRet;
        }       
/*--------- recover */
        else if(strcmp(argv[1],"recover") == 0)
        {
          iRet = RecoverScan(self,pSics,pCon);
          if(iRet)
          {
            SCSendOK(pCon);
          }
          return iRet;
        }    
/*----------- setchannel */
        else if(strcmp(argv[1],"setchannel") == 0)
        {
           if(argc < 3)
           {
             SCWrite(pCon,"ERROR: setchannel expects an integer argument",eError);
             return 0;
           }
           /* convert to int */
           iRet = Tcl_GetInt(pSics->pTcl,argv[2],&iChannel);
           if(iRet != TCL_OK)
           {
             sprintf(pBueffel,"ERROR: expected integer, got %s", argv[2]);
             SCWrite(pCon,pBueffel,eError);
             return 0;
           }
           if( ((iChannel < 0) && (iChannel != -10)) || 
               (iChannel >= GetNMonitor((pCounter)self->pCounterData)) )
           {
             SCWrite(pCon,"ERROR: requested counter channel out of range ",
                     eError);
             return 0;
           } 
           self->iChannel = iChannel;
           SCSendOK(pCon);
           return 1;
        }        
/*--------- command */
        else if(strcmp(argv[1],"command") == 0)
	{
	  /* inquire */ 
           if(argc < 3)
	   {
                sprintf(pBueffel,"%s.command = %s",argv[0],
                        self->pCommand);
                SCWrite(pCon,pBueffel,eValue);
                return 1;    
           }
           /* set case */
           Arg2Text(argc-2,&argv[2],pBueffel,511);
           if(self->pCommand)
              free(self->pCommand);
           self->pCommand = strdup(pBueffel);
           SCSendOK(pCon);
           return 1;
        }
/*--------- integration window */
        else if(strcmp(argv[1],"window") == 0)
        {
            if(argc > 2)
            {
              /* set value */
              iRet = Tcl_GetInt(pSics->pTcl,argv[2],&iChannel);
              if(iRet != TCL_OK)
              {
                sprintf(pBueffel,"ERROR: expected number, got %s",argv[3]);
                SCWrite(pCon,pBueffel,eError);
                return 0;        
              }
              if(iChannel < 0)
              {
                SCWrite(pCon,"ERROR: new integration window size out of range",
                        eError);
                return 0;        
              }
              self->iWindow = iChannel;
              SCSendOK(pCon);
              return 1;
            }            
            else
            {
               /* request the value */
               sprintf(pBueffel,"Integration Window = %d",self->iWindow);
               SCWrite(pCon,pBueffel,eValue);
               return 1;
            }
        }         
/*------------- integrate */
        else if(strcmp(argv[1],"integrate") == 0)
        {
            iRet = ScanIntegrate(self,&fSum,&fVar);
            switch(iRet)
            {
               case INTEGLEFT:
                    SCWrite(pCon,"ERROR: no left limit found for peak",eError);
                    return 0;
                    break;
               case INTEGRIGHT:
                    SCWrite(pCon,"ERROR: no right limit found for peak",eError);
                    return 0;
                    break;
               case INTEGNOPEAK:
                    SCWrite(pCon,"ERROR: no data found for peak",eError);
                    return 0;
                    break;
               case INTEGFUNNYBACK:
                    SCWrite(pCon,"WARNING: background asymmetric or worse",eWarning);
               default:
                    sprintf(pBueffel,"Intensity = %f, Variance = %f",fSum,fVar);
                    SCWrite(pCon,pBueffel,eValue);
                    return 1;
                    break;               
            }
        }    
/*---------- simscan */
        else if(strcmp(argv[1],"simscan") == 0)
        {
            if(argc < 5)
            {
               SCWrite(pCon,"ERROR expected fPos FWHM Height parameters",eError);
               return 0; 
            }
           iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&x);
           if(iRet != TCL_OK)
           {
             sprintf(pBueffel,"ERROR: expected number, got %s",argv[3]);
             SCWrite(pCon,pBueffel,eError);
             return 0;        
           }
           fPos = x;
           iRet = Tcl_GetDouble(pSics->pTcl,argv[3],&x);
           if(iRet != TCL_OK)
           {
             sprintf(pBueffel,"ERROR: expected number, got %s",argv[3]);
             SCWrite(pCon,pBueffel,eError);
             return 0;        
           }
           FWHM = x;
           iRet = Tcl_GetDouble(pSics->pTcl,argv[4],&x);
           if(iRet != TCL_OK)
           {
             sprintf(pBueffel,"ERROR: expected number, got %s",argv[3]);
             SCWrite(pCon,pBueffel,eError);
             return 0;        
           }
           fHeight = x;
           iRet = SimScan(self,fPos,FWHM,fHeight);
           if(!iRet)
           {
             SCWrite(pCon,"ERROR: cannot create simulated scan data",eError);
             return 0;
           }
           SCSendOK(pCon);
           return 1; 
        }        
        else
        {
          sprintf(pBueffel,"ERROR: %s not recognized as subcommand to %s",
                  argv[1], argv[0]);
          SCWrite(pCon,pBueffel,eError);
          return 0;        
        }      
  }      
