
\subsection{Histogram memory}
A histogram memory is the interface to a large multidetector. This is quite
a complex piece of equipment. It does not only provide lots of data but also
has a lot of configuration options. Things which need configuration are:
histogram mode, overflow mode, measurement mode and the layout of the 
histograms. Let's discuss these different modes first.

@d Modes @{
  typedef enum {
                 eHTransparent,
                 eHNormal,
                 eHTOF,
                 eHStrobo,
                 eHRPT,
                 ePSD
               } HistMode;
@}
A histogram memory can be operated in transparent mode. It has not yet been
defined what this means but it is sort of storing raw data from the detector
without any summing or processing. Normal mode is better defined, this is
sorting and summing data from the detector into apropriate bins for each
detector. Time is not resolved. TOF mode means time of flight mode. In this
mode incoming is not only sorted and summed into the correct detector bins
but also resolved in time (which means energy for neutrons). This means for
each detector there is a histogram counts versus time. Similar is
stroboscopic mode (eHStrobo). In stroboscopic mode there is  a histogram
counts versus pulses for each physical detector. The bin switching is done
via a secondary hardware signal or from software. This is useful for
measuring diffraction data versus oscillating environment conditions. eHRPT
is a special mode for the HRPT Cerca detector. It requires special handling,
 this is why there is a special flag.

@d Modes @{
   typedef enum {
                 eOIgnore,
                 eOCeil,
                 eOCount,
                 eReflect
                } OverFlowMode;
@} 
Histogram memories may support different schemes for handling overflow
conditions. In this condition there are more counts than fit into the
configured
binwidth. The simplest thing to do is to ignore the condition and simply
wrap over to zero (eOIgnore). The other mode is to keep the bin at the
highest count possible (eOCeil). More sophisticated histogram memories
maintain a separate list where all those overflowed bins are registered.
This is eOCount. eReflect has nothing to do with overflows. It says that the
 histogram should be reflected. This means counter 1 becomes counter max etc. 
 This is special for HRPT. It happens to live in the OverFlowMode enum because
 this is really a sub mode descriptor.

The measurement mode is the simple counter operation mode: wait for a timer
or wait for a monitor to run full.

The layout of the histogram memory (HM) is defined by the rank (i.e. the number
of dimensions of the HM, the number of points in each dimension and by the
binwidth in bits for each bin.  For TOF and stroboscopic modes information
about the binning in time or pulses is needed as well. Needless to say that
these values have to match the geometry of the detector.

Histograms usually have a number type associated with them. In order to
minimise conversion overhead in the logical object, the data size will
defined by a typedef, HistInt. 

There is a scheme for handling all this configuration information
which may even be more for a Histogram memory with a specific
driver. There is a dictionary of configuration options in the logical
histogram memory object. These options can be set with a special
command. Then on initialisation first the logical histogram memory
evaluates the general options and then the driver in its Config
function evaluates the driver specific options.


\subsubsection{The Histogram memory driver}
Adhering to the Sics paradigm  of dividing any device into a logical device
and a hardware driver, the Sics histogram memory needs drivers as well. This
section  describes this driver interface. For an overview, see the structure
definition:

@d HistType @{
   typedef struct __HistDriver {
                               /* configuration data */
                                 HistMode eHistMode;
                                 OverFlowMode eFlow;
                                 int iRank;
                                 int iDims[MAXDIM];
                                 int nDim;
                                 int iLength;
                                 int iBinWidth;
                                 float fTime[MAXCHAN];
                                 int iTimeChan;
                               /* counting operations data */
                                 CounterMode  eCount;
                                 float fCountPreset;
                               /* status flags */
                                 int iReconfig;
                                 int iUpdate;
                               /* interface functions */
                                 int (*Configure)(pHistDriver self,
                                               SConnection *pCon,
                                               pStringDict pOpt,
                                               SicsInterp *pSics);
                                 int (*Start)(pHistDriver self, 
                                           SConnection *pCon);
                                 int (*Halt)(pHistDriver self);
                                 int (*GetCountStatus)(pHistDriver self,
                                                    SConnection *pCon);
                                 int (*GetError)(pHistDriver self, 
                                              int *iCode,
                                              char *perror,
                                              int iErrlen);
                                 int (*TryAndFixIt)(pHistDriver self,
                                                 int iCode);
                                 int (*GetData)(pHistDriver self,
                                             SConnection *pCon);
                                 int (*GetHistogram)(pHistDriver self,
                                                  SConnection *pCon,
                                                  int i,
                                                  int iStart, int iEnd,
                                                  HistInt *pData);

                                 int (*SetHistogram)(pHistDriver self,
                                                  SConnection *pCon,
                                                  int i,
                                                  int iStart, int iEnd,
                                                  HistInt *pData);
                                 long (*GetMonitor)(pHistDriver self, 
                                                    int i,
                                                    SConnection *pCon);
                                 float (*GetTime)(pHistDriver self,
                                                  SConnection *pCon);
                                 int (*Preset)(pHistDriver self,
                                            SConnection *pCon,
                                            HistInt iVal);
                                 int (*Pause)(pHistDriver self,
                                              SConnection *pCon);
                                 int (*Continue)(pHistDriver self,
                                                 SConnection *pCon);
                                 int (*FreePrivate)(pHistDriver self);
                                 void *pPriv;
                               } HistDriver;
@}

Quite a lot, but a histogram memory is quite a complex piece of equipment.
The configuration information is in the elements EhistMode, eOverFlowMode,
iRank, iDims and iBinWidth fields. iDim and nDim desribe the logical
dimensions of the histogram memory. These may be different from the
dimensions used for data transfer. For instance the SANS detector is
handled internally as 1600+ numbers where it really is a filed o
128*128.
 Additionally there is an array of
floating point values which denote the time binning for time-o-flight
operation or the stroboscopic binning axis in stroboscopic mode.

The fields fPreset and CounterMode hold the counting parameter data.

Than there are two status fields. The first is iReconfig. This will be set
to true, whenever any changes to the configuration to the HM are made. This
will be tested against when starting a measurement and will force a
configuration call to be issued. A call to the interface function Configure
clears this flag. The other flag is iUpdate. This is only useful when an in
memory copy of the histogrammed data is maintained on the host computer.
This flag is set when a count gets started and gets cleared when counting is
finished and all data has been transferred. 

The next part defines the hardware interface functions to the histogram
memory. Each of these functions must be defined by any complete
implementation of a HM driver. If not stated otherwise these functions
return 1 on success and 0 on failure. All functions take a pointer to their
HistDriver structure as first parameter. Many functions have a pointer to an
SConnection as parameter. This connection will be used for error reporting.


\begin{itemize}
\item {\bf Configure} configures the histogram memory to the specifications
given in the fields of the HMdriver structure. Further  driver specific
information can be read from the options dictionary passed in. 
\item {\bf Start} starts a counting operation according to the current
settings of the counter mode parameters.
\item {\bf Halt} implements an emergency stop of a counting operation.
\item {\bf GetCountStatus} serves to monitor the status of the counting
operation. Possible return values to this call are:
\begin{itemize}
\item HWBUSY when still counting.
\item HWNoBeam when the monitor is to low.
\item HWIDLE or OKOK when nothing is going on.
\item HWFault when there is an error on the device.
\end{itemize}
\item {\bf GetError} will be called whenever an error has been detected on
the device. The task is to put an internal error code into the iCode
parameter. The string parameter error will be filled with a text description
of the error. But maximum iLen characters will be transferred to the error
string in order to protect against memory corruption. Therefore iLen must be
the maximum field length of error. 
\item {\bf TryAndFixIt} is the next function called in case of an error on
the device. Its second parameter is the internal code obtained in the ICode
parameter of the call to GetError. The task of this function is to examine
the error code and do whatever is possible in software to fix the problem.
TryAndFixIt returns one of the following values:
\begin{itemize}
\item MOTREDO when the error could be fixed, but the upper level code will
need to rerun the command which failed.
\item MOTFAIL when the software is unable to fix the problem and a real
mechanic  with a hammer is needed (or somebody able to reboot!).
\item MOTOK when the error was fixed and nor further action is necessary.
\end{itemize}
\item {\bf GetData} transfers all the data collected in the HM into the
host computers memory.  
\item {\bf GetHistogram} copies the histogram number i into the data space
given by the pointer to a long array. A conversion from different binwidth
to long is performed as well.
\item {\bf SetHistogram} presets the histogram number i with the data 
given in lData. A conversion from different binwidth
to long is performed as well. iStart and iStop define the start and end of
the stretch of histogram to replace.
\item {\bf GetMonitor} returns the counts in the monitor i. Returns a
negative value on error. The error will have been printed to pCon.
\item {\bf GetTime} returns the actual counting time.
\item {\bf Preset} initializes the histogram memory to the value given by
iVal.
\item {\bf Pause} pauses data collection.
\item {\bf Continue} continues a paused data collection.
\item {\bf FreePrivate} will be called automatically by DeleteHistDriver and
has the task to remove the private data installed by implementations of an
actual histogram memory driver.
\end{itemize}

The last entry in the HistDriver structure is a pointer to void. Rather then use the overlay structure as with motor drivers, histogram
memory stores driver specific information in a driver specific sub
data structure. This is the pointer to pPrivate. KillPrivate is a
function which is able to delete the driver specific data structure
properly.  

As all the burden is up to the implementation of the histogram memory driver
only these few functions operate on histogram memory drivers in general:

@d HistDrivProt @{
   pHistDriver CreateHistDriver(pStringDict pDict);
   void        DeleteHistDriver(pHistDriver self);
   int         HistDriverConfig(pHistDriver self, pStringDict pOpt,
                                SConnection *pCon);
@}

CreateHistDriver creates a new HistDriver data structure and returns it. Or
NULL when the memory is exhausted. It also initialises the options database
in pDict to the apropriate values.


DeleteHistDriver removes a histogram memory driver from memory. It will
automatically try and call Freeprivate in order to remove driver specific
data. Than an the rest is removed. After this call self will point to
rubbish.


\subsubsection{The histogram memory object}
Most of the HM data will be held with the driver as it is needed there for
performing operations. Accordingly the datastructure associated with the
histogram memory object is fairly simple:
@d HistST @{
   typedef struct __HistMem {
                              pObjectDescriptor pDes;
                              int iAccess;
                              int iExponent;
                              pHistDriver pDriv;
                              int iInit;
                              pICountable pCountInt;
                              pICallBack  pCall;
                              pStringDict pOption;
                              HistInt *iLocalData;
                              int iLocalLength;
                              int iLocalUpdate;
                              time_t tLocal;
                              int iUpdateIntervall;
                            } HistMem;
@}
According to the general Sics object interface the first field is the object
descriptor. Note, that the histogram memory has to adhere to the countable
objects interface. iAccess is the access code used to control user
interaction with the HM. iExponent is the force of 10 used for calculating
the actual preset value for counting in monitor mode.
However, note, that all configuration commands will
require Manager privilege at least. Then there is a pointer to the
driver followed by pointers to the interfaces implemented by the histogram
 memory. pOption is a string dictionary of configuration options for the
 histogram memory.

In order to save network bandwidth and for efficiency the histogram memory
 object buffers the histogram memory in memory. The histogram itself resides
 in iLocalData. iLocalLength is the length of iLocalData. iLocalUpdate is a
 flag which will be set when counting operations (histogram changes ) are 
 going on and cleared when the histogram has been completely read. 
 When counting the local data will be updated only at certain intervalls. 
 This is a configuration option. iUpdateIntervall is that intervall in 
 seconds, tLocal is the time for the next scheduled update.    


The interaction with the histogram memory can be classified into four
groups: basic initialisation and destruction, configuration, counting and
data retrieval. The first group to look at are the basics:

@d Protos @{
   pHistMem CreateHistMemory(char *drivername);
   void     DeleteHistMemory(void *self);
@}

CreateHistMem creates a new histogram memory.
On error this
call returns NULL. On success a pointer to the new histogram memory object.
CreateHistMem does NOT configure anything! A driver gets selected according
to the driver name.

DeleteHistMemory removes a histogram memory from computer memory.
 Any references to self afterwards will
point to rubbish.

The next group of functions refer to configuration. 
@d Protos @{
   int HistGetOption(pHistMem self, char *name, char *result, int iResultLen);
   int HistSetOption(pHistMem self, char *name, char *value);
   int HistConfigure(pHistMem self, SConnection *pCon, SicsInterp *pSics);
@}

HistGetOption caters for the retrieval of the current option given in name.
Maximum iResultLen characters of result will be copied into result, or an
error message if things go wrong. 

HistSetOption sets the option name to value specified in value. No error
checking except availability of the option and permission is done here.

HistConfigure updates the internal datastructures from the dictionary and
does the actual configuration of the HM. Tons of error messages will be
printed to pCon.

Valid names for the options in the dictionary are all the names in the
histogram datastructure. Please note, that counting options are handled
separately (see below). Additionally there may be driver specific options
available. For iDim iRank numbers are expected which represent the
dimensions of the HM.

The functions for counting and manipulation of counting parameters have been
separated from the rest of the configuration. The reason is that the main
configuration will only be performed by highly privileged users, whereas
the counting operations will be accessible by normal users. Counting is
controlled by the following functions:
@d Protos @{
  float GetHistPreset(pHistMem self);
  int   SetHistPreset(pHistMem self, float fVal);
  CounterMode GetHistCountMode(pHistMem self);
  int         SetHistCountMode(pHistMem self, CounterMode eNew);
  long GetHistMonitor(pHistMem self, int i, SConnection *pCon);
  const float *GetHistTimeBin(pHistMem self, int *iLength);
  int GetHistLength(pHistMem self);
  int GetHistDim(pHistMem self, int iDim[MAXDIM], int *nDim);
  float GetHistCountTime(pHistMem self,SConnection *pCon);
  int HistDoCount(pHistMem self, SConnection *pCon);
  int HistBlockCount(pHistMem self, SConnection *pCon);

@}    
The first four functions are simple parameter enquiry and manipulation
functions. GetHistMonitor returns the count on monitor number i for the
histogram memory. This function returns a negative value when the value
specified for i is invalid.

HistDoCount actually starts a counting operation. It will not
block and wait for counting to finish. Please note, that many counting
manipulation functions are hidden in the functions of the countable
interface, which the HM has to implement.

HistBlockCount also starts counting. But will block until counting has
finished. 

Another set of functions is needed for manipulation of the data in the
histogram memory:
@d Protos @{
   int SetHistogram(pHistMem self, SConnection *pCon,
                    int i,int iStart, int iEnd, HistInt *lData);
   int GetHistogram(pHistMem self, SConnection *pCon,
                    int i,int iStart, int iEnd, HistInt *lData, int iDataLen);
   HistInt *GetHistogramPointer(pHistMem self,SConnection *pCon);
   int GetHistogramDirect(pHistMem self, SConnection *pCon,
                          int i, int iStart, int iEnd, 
                          HistInt *lData, int iDataLen);
   int PresetHistogram(pHistMem self, SConnection *pCon, HistInt lVal);
@}
For histogram I/O the following aproach has been taken: Histograms are kept
as linear arrays of data regardless of the layout of the detector. It is the
task of upper level code to map the right histogram to the right position.
This aproach was choosen for two reasons: 1.) simplification of interface,
2.) easier to retrieve smaller chunks of data at a time.
  
With both SetHistogram and GetHistogram the parameter i denotes the
histogram to retrieve. A value of -1 retrieves the whole lot. iStart and
iEnd allow for extraction of a subset of a histogram. These values get
ignored when trying to retrieve a whole HM content.  These routines
perform conversion to and from long to the binwidth of the HM. SetHistogram
initialises the HM from the lData provided. GetHistogram reads an histogram
into lData but maximum iDataLen items. PresetHistogram presets the HM to the
value lVal. Can be used to clear the HM.  

GetHistogram and GetHistogramPointer try to buffer the data when
 possible and configured. The configuration happens through the
 definition of an update intervall.   GetHistogramDirect never buffers
 but goes for the histogram memory directly.

The histogram memory object buffers the histograms for a adjustable
period of time. GetHistogramPointer retrieves a pointer to the local
histogram buffer. It also makes sure, that the histogram has been
updated if appropriate. This is provided for efficiency and saves some
memory copying and duplication of data during operations. Thus memory
consumption can be reduced. However, the drawback is that you mess
directly with the histogram memory content which is potentially
dangerous. Use this method with great care! 


A last group of functions are those needed to interface to the Sics
interpreter:
@d Protos @{
   int MakeHistMemory(SConnection *pCon, SicsInterp *pSics, void *pData,
                      int argc, char *argv[]);

   int HistAction(SConnection *pCon, SicsInterp *pSics, void *pData,
                      int argc, char *argv[]);
    
@}

MakeHistMem is supposed to be called with two parameters: name and driver
which denote the name of the HM object and the type of driver to use. If all
is well, this call will create a command named name. Remember, that
the HM is
not yet configured!

HistAction is supposed to be where the action goes. HistAction understands
the commands:\begin{itemize}
\item {\bf name config option value} sets a configuration option.
\item {\bf name init} configures the HM.
\item {\bf name Preset val} returns the preset value if val is missing, else
it sets it.
\item {\bf name Mode val} returns the counting mode  if val is missing, else
it sets it.
\item {\bf name count} starts a counting operation.
\item {\bf name get number} gets histogram number. -1 as histogram number
gets all.
\item {\bf name set number val........} sets histogram number to the values
following.
\item {\bf name clear val} sets all the HM to val.
\end{itemize}

@o HistMem.h -d @{
/*--------------------------------------------------------------------------
	            H I S T M E M 

  header for the histogram memory object for SICS.

  copyright: see implementation file.
  Mark Koennecke, April 1997
-----------------------------------------------------------------------------*/
#ifndef SICSHISTMEM
#define SICSHISTMEM
#define MAXDIM 3

  typedef struct __HistDriver *pHistDriver;
  typedef struct __HistMem    *pHistMem;
/*-------------------------------------------------------------------------*/
  typedef int HistInt;
/*
  32 bit integer on a DigitalUnix
*/
@< Modes @>
/*--------------------------------------------------------------------------*/
@< Protos @>

#endif
@}

@o HistDriv.i -d @{
/*---------------------------------------------------------------------------
			H I S T D R I V
  internal header file which includes the definition of the Histogram memory
  driver structure.

  Mark Koennecke, April 1997
----------------------------------------------------------------------------*/
#ifndef SICSHISTDRIV
#define SICSHISTDRIV
#define MAXCHAN 16834 

@< HistType@>
@< HistDrivProt @>

#endif
@}

@o HistMem.i -d @{
/*---------------------------------------------------------------------------
			H I S T M E M -- Internal
  internal header file which includes the definition of the Histogram memory
  data structure.

  Mark Koennecke, April 1997
----------------------------------------------------------------------------*/
#ifndef SICSHISTMEMINT
#define SICSHISTMEMINT
@< HistST@>

#endif
@}



    
