Back Midas Rome Roody Rootana
  Midas DAQ System, Page 114 of 136  Not logged in ELOG logo
ID Date Authordown Topic Subject
  193   21 Jan 2005 John M O'DonnellBug ReportPersistency problem with h1_book() & co
> The current h1_book() macros (and the previous example analyzer code) have an
> odd persistency problem: for example, the user wants to change some histogram
> limits, edits the h1_book() calls, rebuilds and restarts the analyzer, starts a
> new run, and observes that all histograms are filled using the old limits, his
> changes "did not take". The user panics, I get paged during the Holy Lunch Hour,
> everybody is unhappy.
> 
> This is what I think happens:
> 
> 1) analyzer starts
> 2) LoadRootHistgrams() loads old histograms from file

I can't get onto cvs@midas.psi.ch right now
(cvs update
cvs@midas.psi.ch's password: 
Permission denied, please try again.)

but when I changed LoadRootHistograms a few days ago I left it as:

    } else if (obj->InheritsFrom( "TH1")) {

      // still don't know how to do TH1s

so h1_book() is creating the first and only copy of the histograms.
I am able to create new histogram limits.
I don't get the memory leak problems.

However I have seen the memory leak problems before, and they are real.
They must be dealt with either by (1) first deleteing the old histogram
or (2) ensuring that histogram names are unique in the whole application
(different modules/folders can not use the same histogram names).

I will return to this once I can do a cvs update for midas.

John.

> 3) user code calls h1_book()
> 4) h1_book template in midas.h does this (roughly):
>       hist = (TH1X *) gManaHistosFolder->FindObjectAny(name);
>       if (hist == NULL) {
>          hist = new TH1X(name, title, bins, min, max);
> 5) since the histogram already exists (loaded from the file, with the old
> limits), the TH1X constructor is not called at all, new histogram limits are
> utterly ignored.
> 
> A possible solution is to unconditionally create the ROOT objects, like I do in
> the example code posted at <a
href="http://dasdevpc.triumf.ca:9080/Midas/191">http://dasdevpc.triumf.ca:9080/Midas/191</a>.
That code
> produces an annoying warning from ROOT about possible memory leaks. This could
> be fixed by adding a two liner to "find and delete" the object before it is
> created, trippling the number of user code lines per histogram (find & delete,
> then create). Highly ugly.
> 
> midas.h macros (h1_book & co) can be fixed by adding checks for histogram limits
> and such, but I would much prefer a generic solution/convention that would work
> for arbitrary ROOT objects without MIDAS-specific wrappers (think TProfile,
> TGraph, etc...).
> 
> Any suggestions?
> 
> K.O.
  196   25 Jan 2005 John M O'DonnellBug ReportPersistency problem with h1_book() & co
So now that cvs is reachable again I have confirmed that
the code segment
 
     } else if (obj->InheritsFrom( "TH1")) {
 
       // still don't know how to do TH1s

is indeed still present.
If you want me to look at this some more, you need to provide some code to exhibit the problem.

John.

> > The current h1_book() macros (and the previous example analyzer code) have an
> > odd persistency problem: for example, the user wants to change some histogram
> > limits, edits the h1_book() calls, rebuilds and restarts the analyzer, starts a
> > new run, and observes that all histograms are filled using the old limits, his
> > changes "did not take". The user panics, I get paged during the Holy Lunch Hour,
> > everybody is unhappy.
> > 
> > This is what I think happens:
> > 
> > 1) analyzer starts
> > 2) LoadRootHistgrams() loads old histograms from file
> 
> I can't get onto cvs@midas.psi.ch right now
> (cvs update
> cvs@midas.psi.ch's password: 
> Permission denied, please try again.)
> 
> but when I changed LoadRootHistograms a few days ago I left it as:
> 
>     } else if (obj->InheritsFrom( "TH1")) {
> 
>       // still don't know how to do TH1s
> 
> so h1_book() is creating the first and only copy of the histograms.
> I am able to create new histogram limits.
> I don't get the memory leak problems.
> 
> However I have seen the memory leak problems before, and they are real.
> They must be dealt with either by (1) first deleteing the old histogram
> or (2) ensuring that histogram names are unique in the whole application
> (different modules/folders can not use the same histogram names).
> 
> I will return to this once I can do a cvs update for midas.
> 
> John.
> 
> > 3) user code calls h1_book()
> > 4) h1_book template in midas.h does this (roughly):
> >       hist = (TH1X *) gManaHistosFolder->FindObjectAny(name);
> >       if (hist == NULL) {
> >          hist = new TH1X(name, title, bins, min, max);
> > 5) since the histogram already exists (loaded from the file, with the old
> > limits), the TH1X constructor is not called at all, new histogram limits are
> > utterly ignored.
> > 
> > A possible solution is to unconditionally create the ROOT objects, like I do in
> > the example code posted at <a
> href="<a
href="http://dasdevpc.triumf.ca:9080/Midas/191">http://dasdevpc.triumf.ca:9080/Midas/191</a>">http://dasdevpc.triumf.ca:9080/Midas/191"><a
href="http://dasdevpc.triumf.ca:9080/Midas/191</a>">http://dasdevpc.triumf.ca:9080/Midas/191</a></a></a>.
> That code
> > produces an annoying warning from ROOT about possible memory leaks. This could
> > be fixed by adding a two liner to "find and delete" the object before it is
> > created, trippling the number of user code lines per histogram (find & delete,
> > then create). Highly ugly.
> > 
> > midas.h macros (h1_book & co) can be fixed by adding checks for histogram limits
> > and such, but I would much prefer a generic solution/convention that would work
> > for arbitrary ROOT objects without MIDAS-specific wrappers (think TProfile,
> > TGraph, etc...).
> > 
> > Any suggestions?
> > 
> > K.O.
  197   25 Jan 2005 John M O'DonnellSuggestionHOWTO create ROOT objects in the MIDAS analyzer
> (preliminary, untested. I will keep this updated as I get testing feedback)
> 
> With recent changes to mana.c, creation of user ROOT objects in the MIDAS
> analyser has changed. Here is the new example code for creating ROOT objects
> that are visible in ROODY and are saved into the histogram file.
> 
> 1) in the "global" context (outside of any function)
> 
> #include <TH1D.h>
> #include <TProfile.h>
> 
> static TH1D* gMyHist1 = 0;
> static TProfile* gMyHist2 = 0;
> 
> 2) In the analyzer "init" or "begin run" method, create the histogram:
> 
> //extern TFolder *gManaHistosFolder; // from midas.h
> gMyHist1 = new TH1D("gMyHist1",...);
> gMyHist2 = new TProfile("gMyHist2",...);
> gManaHistosFolder->Add(gMyHist1);
> gManaHistosFolder->Add(gMyHist2);
> 
> (note: this will produce an warning about "possible memory leak")
> 
> 3) In the per-event method, fill the histograms
> 
> gMyHist1->Fill(x);
> gMyHist2->Fill(x,y);
> 
> K.O.


the book functions provide a convenient place to check against object duplication
and memory leaks etc., and a place to ensure that consistent subfolders are being
used.  eg. a while back we decided that TCutGs should be in a "cuts" subfolder.

To extend the booking to TProfile is fairly easy.  In fact if you want to
use the simple constructor TProfile::TProfile (const char *, const char *, Int_t,
Axis_t, Axis_t), then you could infact just use h1_book<TProfile>.

It now seems to me that the names h1_book, h2_book, cut_book are all too long
and even more upsetting are inconsistent.  Some of them are templates (most) and
some are not.  Perhaps they should all be templates, and all have the same name.
The attached patch accomplishes this (without deleting the old names).  With this
patch you can now do

gMyHist1 = book<TProfile>( "gMyHist2",...);

New book templates are needed when you (1) wish to change the subfolder, or (2)
need to use a different argument list in the constructor.  If you need help with
this for the TProfile constructors which are different from TH1D constructors then
let me know.  They should be easy to do.

For TGraph at lot depends on how you want to initialise the data points.
Attachment 1: book.patch
? linux
? examples/experiment/analyzer
? examples/experiment/frontend
? examples/slowcont/scfe
? gui/hvedit/qt/Makefile
? gui/hvedit/qt/hvEdit
? gui/hvedit/qt/moc_Qt_Connect.cpp
? gui/hvedit/qt/moc_Qt_Pwd.cpp
? gui/hvedit/qt/moc_Qt_hvEdit.cpp
? gui/hvedit/qt/moc_cmExperiment.cpp
? gui/hvedit/qt/Qt_Dlgs/Qt_Connect_Base.cpp
? gui/hvedit/qt/Qt_Dlgs/Qt_Connect_Base.h
? gui/hvedit/qt/Qt_Dlgs/Qt_Pwd_Base.cpp
? gui/hvedit/qt/Qt_Dlgs/Qt_Pwd_Base.h
? gui/hvedit/qt/Qt_Dlgs/Qt_fileList.cpp
? gui/hvedit/qt/Qt_Dlgs/Qt_fileList.h
? gui/hvedit/qt/Qt_Dlgs/Qt_hvEditAbout.cpp
? gui/hvedit/qt/Qt_Dlgs/Qt_hvEditAbout.h
? gui/hvedit/qt/Qt_Dlgs/Qt_hvEdit_Base.cpp
? gui/hvedit/qt/Qt_Dlgs/Qt_hvEdit_Base.h
? gui/hvedit/qt/Qt_Dlgs/moc_Qt_Connect_Base.cpp
? gui/hvedit/qt/Qt_Dlgs/moc_Qt_Pwd_Base.cpp
? gui/hvedit/qt/Qt_Dlgs/moc_Qt_fileList.cpp
? gui/hvedit/qt/Qt_Dlgs/moc_Qt_hvEditAbout.cpp
? gui/hvedit/qt/Qt_Dlgs/moc_Qt_hvEdit_Base.cpp
? gui/hvedit/qt/help/moc_helpwindow.cpp
? include/.midas.h.swp
===================================================================
RCS file: /usr/local/cvsroot/midas/include/midas.h,v
retrieving revision 1.148
diff -r1.148 midas.h
2272a2273,2275
>    template<typename T>
>    T EXPRT *book (const char *name, const char *title,
> 		  int bins, double min, double max)
2276,2278d2278
<    template<typename TH1X>
<    TH1X EXPRT *h1_book(const char *name, const char *title,
< 		       int bins, double min, double max)
2280c2280
<       TH1X *hist;
---
>       T *hist;
2284c2284
<          hist = (TH1X *) gManaHistosFolder->FindObjectAny(name);
---
>          hist = (T *) gManaHistosFolder->FindObjectAny(name);
2286c2286
<          hist = (TH1X *) ((TFolder *)gHistoFolderStack->Last())->FindObjectAny(name);
---
>          hist = (T *) ((TFolder *)gHistoFolderStack->Last())->FindObjectAny(name);
2289c2289
<          hist = new TH1X(name, title, bins, min, max);
---
>          hist = new T(name, title, bins, min, max);
2299,2301c2299,2300
<    template<typename TH1X>
<    TH1X EXPRT *h1_book(const char *name, const char *title,
< 		       int bins, double edges[])
---
>    template<typename T>
>    T EXPRT *book(const char *name, const char *title, int bins, double edges[])
2303c2302
<       TH1X *hist;
---
>       T *hist;
2307c2306
<          hist = (TH1X *) gManaHistosFolder->FindObjectAny(name);
---
>          hist = (T *) gManaHistosFolder->FindObjectAny(name);
2309c2308
<          hist = (TH1X *) ((TFolder *)gHistoFolderStack->Last())->FindObjectAny(name);
---
>          hist = (T *) ((TFolder *)gHistoFolderStack->Last())->FindObjectAny(name);
2312c2311
<          hist = new TH1X(name, title, bins, edges);
---
>          hist = new T(name, title, bins, edges);
2322,2325c2321,2324
<    template<typename TH2X>
<    TH2X EXPRT *h2_book(const char *name, const char *title,
< 	     	       int xbins, double xmin, double xmax,
<                        int ybins, double ymin, double ymax)
---
>    template<typename T>
>    T EXPRT *book(const char *name, const char *title,
> 	     	 int xbins, double xmin, double xmax,
>                  int ybins, double ymin, double ymax)
2327c2326
<       TH2X *hist;
---
>       T *hist;
2331c2330
<          hist = (TH2X *) gManaHistosFolder->FindObjectAny(name);
---
>          hist = (T *) gManaHistosFolder->FindObjectAny(name);
2333c2332
<          hist = (TH2X *) ((TFolder *)gHistoFolderStack->Last())->FindObjectAny(name);
---
>          hist = (T *) ((TFolder *)gHistoFolderStack->Last())->FindObjectAny(name);
2336c2335
<          hist = new TH2X(name, title, xbins, xmin, xmax, ybins, ymin, ymax);
---
>          hist = new T(name, title, xbins, xmin, xmax, ybins, ymin, ymax);
2346,2349c2345,2348
<    template<typename TH2X>
<    TH2X EXPRT *h2_book(const char *name, const char *title,
< 	  	       int xbins, double xmin, double xmax,
<                        int ybins, double yedges[])
---
>    template<typename T>
>    T EXPRT *book(const char *name, const char *title,
> 	         int xbins, double xmin, double xmax,
>                  int ybins, double yedges[])
2351c2350
<       TH2X *hist;
---
>       T *hist;
2355c2354
<          hist = (TH2X *) gManaHistosFolder->FindObjectAny(name);
---
>          hist = (T *) gManaHistosFolder->FindObjectAny(name);
2357c2356
<          hist = (TH2X *) ((TFolder *)gHistoFolderStack->Last())->FindObjectAny(name);
---
>          hist = (T *) ((TFolder *)gHistoFolderStack->Last())->FindObjectAny(name);
2360c2359
<          hist = new TH2X(name, title, xbins, xmin, xmax, ybins, yedges);
---
>          hist = new T(name, title, xbins, xmin, xmax, ybins, yedges);
2370,2373c2369,2372
<    template<typename TH2X>
<    TH2X EXPRT *h2_book(const char *name, const char *title,
< 		       int xbins, double xedges[],
<                        int ybins, double ymin, double ymax)
---
>    template<typename T>
>    T EXPRT *book(const char *name, const char *title,
> 		 int xbins, double xedges[],
>                  int ybins, double ymin, double ymax)
2375c2374
<       TH2X *hist;
---
>       T *hist;
2379c2378
<          hist = (TH2X *) gManaHistosFolder->FindObjectAny(name);
---
>          hist = (T *) gManaHistosFolder->FindObjectAny(name);
2381c2380
<          hist = (TH2X *) ((TFolder *)gHistoFolderStack->Last())->FindObjectAny(name);
---
>          hist = (T *) ((TFolder *)gHistoFolderStack->Last())->FindObjectAny(name);
2384c2383
<          hist = new TH2X(name, title, xbins, xedges, ybins, ymin, ymax);
---
>          hist = new T(name, title, xbins, xedges, ybins, ymin, ymax);
2394,2397c2393,2396
<    template<typename TH2X>
<    TH2X EXPRT *h2_book(const char *name, const char *title,
< 		       int xbins, double xedges[],
<                        int ybins, double yedges[])
---
>    template<typename T>
>    T EXPRT *book(const char *name, const char *title,
> 		 int xbins, double xedges[],
>                  int ybins, double yedges[])
2399c2398
<       TH2X *hist;
---
>       T *hist;
2403c2402
<          hist = (TH2X *) gManaHistosFolder->FindObjectAny(name);
---
>          hist = (T *) gManaHistosFolder->FindObjectAny(name);
2405c2404
<          hist = (TH2X *) ((TFolder *)gHistoFolderStack->Last())->FindObjectAny(name);
---
>          hist = (T *) ((TFolder *)gHistoFolderStack->Last())->FindObjectAny(name);
2408c2407
<          hist = new TH2X(name, title, xbins, xedges, ybins, yedges);
---
>          hist = new T(name, title, xbins, xedges, ybins, yedges);
2422,2423c2421,2422
<    #define H1_BOOK(n,t,b,min,max) (h1_book<TH1F>(n,t,b,min,max))
<    #define H2_BOOK(n,t,xb,xmin,xmax,yb,ymin,ymax) (h2_book<TH2F>(n,t,xb,xmin,xmax,yb,ymin,ymax))
---
>    #define H1_BOOK(n,t,b,min,max) (book<TH1F>(n,t,b,min,max))
>    #define H2_BOOK(n,t,xb,xmin,xmax,yb,ymin,ymax) (book<TH2F>(n,t,xb,xmin,xmax,yb,ymin,ymax))
2425c2424,2469
<    TCutG *cut_book( const char *name);
---
>    /*
>     * The following obsolete calls are here for backwards compatibility.
>     * They are inlined, so incur no performance hit.
>     */
>    template<typename TH1X>
>    inline TH1X EXPRT *h1_book(const char *name, const char *title,
> 		              int bins, double min, double max) {
>      return book<TH1X>( name, title, bins, min, max);
>    }
>    template<typename TH1X>
>    inline TH1X EXPRT *h1_book(const char *name, const char *title,
> 	         	      int bins, double edges[]) {
>      return book<TH1X>( name, title, bins, edges);
>    }
>    template<typename TH2X>
>    inline TH2X EXPRT *h2_book(const char *name, const char *title,
> 	       	              int xbins, double xmin, double xmax,
>                               int ybins, double ymin, double ymax) {
>      return book<TH2X>( name, title, xbins, xmin, xmax, ybins, ymin, ymax);
>    }
>    template<typename TH2X>
>    inline TH2X EXPRT *h2_book(const char *name, const char *title,
> 	  	              int xbins, double xmin, double xmax,
>                               int ybins, double yedges[]) {
>      return book<TH2X>( name, title, xbins, xmin, xmax, ybins, yedges);
>    }
>    template<typename TH2X>
>    inline TH2X EXPRT *h2_book(const char *name, const char *title,
> 		              int xbins, double xedges[],
>                               int ybins, double ymin, double ymax) {
>      return book<TH2X>( name, title, xbins, xedges, ybins, ymin, ymax);
>    }
>    template<typename TH2X>
>    inline TH2X EXPRT *h2_book(const char *name, const char *title,
> 		              int xbins, double xedges[],
>                               int ybins, double yedges[]) {
>      return book<TH2X>( name, title, xbins, xedges, ybins, yedges);
>    }
> 
>    template<typename T>
>    T EXPRT *book (const char *name); // generic object not implemented
>    /*
>     * but some simple objects are implemented via specializations
>     */
>    template<>
>    TCutG EXPRT *book<TCutG> (const char *name);
? src/.mana.c.swp
Index: src/mana.c
===================================================================
RCS file: /usr/local/cvsroot/midas/src/mana.c,v
retrieving revision 1.132
diff -r1.132 mana.c
3945c3945,3946
< TCutG *cut_book (const char *name) {
---
> template<>
> TCutG EXPRT *book<TCutG> (const char *name) {
  198   25 Jan 2005 John M O'DonnellBug Reporthistograms not saved in replay mode
is there a reason why histograms are not saved after a replay?

   /* save histos if requested */
   if (out_info.histo_dump && clp.online) {
                              ^^^^^^^^^^

perhaps the && should be ||?
  348   23 Feb 2007 John M O'DonnellInfoRFC- support for writing to removable hard disk storage
We stopped using tapes at Los Alamos a while ago.  The model we use is:

write data with mlogger to a local RAID system.  This is NFS mounted read only on teh analysis machines, and
becomes the working copy for most tasks.  Copy data to external hardrives.  We have been using USB.  The USB
system is sometime a little flaky (lnux 2.4.21-7, so we have a computer dedicated to this task.  The USB driver
can be reloaded, or if the user is not so knowledgeable, the copmuter can be rebooted.  users on this computer
have sudo privs, so they can format hard drives.  The disks are inserted into boxes while in use, and stored on
a shelf for data archival, so we don't have a lot of enclosures.

I use the automounter to mount and unmount the drives.  With a 10 second timeout, the user needs only to wait a
few seconds before unplugging the disk.  (cat /proc/mounts allows them to check if they want.) dmesg allows
them to find the drive letter.  This works for any device which appears later as a SCSI disk.  The automounter
manages /mnt/usb for vfat formatted devices, and /mnt/usbl for ext3 formatted devices (preferred for data
archiving).

autofs config files are:

/etc/auto.usb

# This is an automounter map and it has the following format
# key [ -mount-options-separated-by-comma ] location
# Details may be found in the autofs(5) manpage
 
*       -fstype=auto,nosuid,nodev,umask=0000,noatime    :/dev/&

/etc/auto.usbl

# This is an automounter map and it has the following format
# key [ -mount-options-separated-by-comma ] location
# Details may be found in the autofs(5) manpage
 
*       -fstype=auto,nosuid,nodev       :/dev/&

/etc/auto.master contains

/mnt/usb                /etc/auto.usb  --timeout=10
/mnt/usbl               /etc/auto.usbl --timeout=10


John.

> At triumf, we are developing a system to use removable hard drives to store data collected by midas 
> daq stations. The basic idea is to replace storage on 300 GB DLT tapes with storage on removable 
> esata, usb2 or firewire 750 GB hard drives.
> 
> To minimize culture shock, we stay as close as possible to the "tape" paradigm. Two removable disks 
> are used in tandem. Data is written to the first removable disk until it is full. Then midas automatically 
> switches to the second disk and asks the operator to replace the full disk with a blank disk. Similar to 
> handling tapes, the operator takes the full disk and stores it on the shelf (offline); takes a blank disk 
> and connects it to the computer. To read data from one of the disks, the operator takes the disk from 
> the shelf and connects it to the daq computer or to some other computer equipped with a compatible 
> removable storage bay. The full data disks are mounted read-only to prevent accidental data 
> modifications.
> 
> Two pieces of software are needed to implement this system:
> 
> 1) midas support for switching to alternate output disks as they become full. Data could be written to 
> the removable disk directly by the mlogger (no extra data copy on local disks) or by the lazylogger 
> (mlogger writes the data to the local disk, then the lazylogger copies it to the removable disk). Writing 
> directly to the removable disk is more efficient as it avoids the one extra data copy operation by the 
> lazylogger.
> 
> 2) a user interface utility for mounting and dismounting removable disks. Handling of removable disks 
> cannot be fully automatic: before unplugging a removable disk, the user has to inform the system; after 
> connecting a removable disk, the user has to tell the system to mount it read-only (for existing data), 
> read-write (to add more data) or to initialize a blank disk (fdisk+mkfs). (Also, some SATA interfaces do 
> not implement automatic hot-plug: they have to be manually told "please look for new disks").
> 
> We are presently evaluating various internal SATA hot-plug enclosures. We evaluated external eSATA 
> and USB2 enclosures and decided not to use them: while the performance is adequate, presence of 
> extra bulky components (eSATA and USB cables, non-standardized power bricks) and the extra cost of 
> eSATA and USB hard drive enclosures makes them unattractive.
> 
> I am open to suggestions and comments. I am most interested in hearing which data path (mlogger or 
> the lazylogger) would be most useful for other users.
> 
> K.O.
  355   27 Feb 2007 John M O'DonnellForumevent builder scalability
At Los Alamos, we have 15+1 frontends - the 15 between them read about 2 or 3
TB/hour and reduce it to 1 to 5 GB/hour which is then sent to the mevb on a 17th
computer.  The 16th frontend handles deadtime issues and scalers (small data rate).

frontends are 1GHz pentium 3, and backend is 2.8GHz dual CPU with hyperthreading.
Interconnect is 100Mb ethernet from frontends to switch, and 1Gb ethernet from
switch to backend.

Our bottle neck is (a) compactPCI backplane reading data from waveform digitizers
to the frontend CPUs and (b) CPU power on the frontend CPUs to analyzer the waveforms.

John
  383   07 Jun 2007 John M O'DonnellSuggestionRFC- ACLs for midas rpc, mserver, mhttpd access
I am in favor of tcp_wrappers.

tcp_wrappers is well understood.

It works well in combination with a firewall.

mhttpd hangs when our security folks scan us.  We are not allowed to block them
with a firewall, but we can use tcpwrappers.

Would it make sense to put the same mechanism on mserver?

the man page for libtcpwrappers.a (taken from the tcpwrappers7.6 tar ball) is
attached. And the output after running it through nroff -man.

The odb is too fragile for security.  It is not understood well enough by many
experimenters.

As you can see I am in favor of tcp_wrappers.  This is mainly because it is part
of an existing and tested security model.  I don't know about the windows
world, but as you can also see, I vote for using something that is already part
of the windows security model.  Here's an example of how well the integrated
security model works:

    if an person is part of an experiment I make sure they can ssh to the
    experiment's computer

    the same rules could provide them with web access

Second is that when a change is needed to the security model then it is easy to
keep it current.  What if somebody restores an old ODB?  What if they setup a
small test with a new ODB?

If mhttpd used tcp_wrappers, then all our machines here at LANL would already be
configured!  No need for
users to do any root access (though those that need it have it anyway).

John.
Attachment 1: hosts_access.3-nroffed
Attachment 2: hosts_access.3
.TH HOSTS_ACCESS 3
.SH NAME
hosts_access, hosts_ctl, request_init, request_set \- access control library
.SH SYNOPSIS
.nf
#include "tcpd.h"

extern int allow_severity;
extern int deny_severity;

struct request_info *request_init(request, key, value, ..., 0)
struct request_info *request;

struct request_info *request_set(request, key, value, ..., 0)
struct request_info *request;

int hosts_access(request)
struct request_info *request;

int hosts_ctl(daemon, client_name, client_addr, client_user)
char *daemon;
char *client_name;
char *client_addr;
char *client_user;
.fi
.SH DESCRIPTION
The routines described in this document are part of the \fIlibwrap.a\fR
library. They implement a rule-based access control language with
optional shell commands that are executed when a rule fires.
.PP
request_init() initializes a structure with information about a client
request. request_set() updates an already initialized request
structure. Both functions take a variable-length list of key-value
pairs and return their first argument.  The argument lists are
terminated with a zero key value. All string-valued arguments are
copied. The expected keys (and corresponding value types) are:
.IP "RQ_FILE (int)"
The file descriptor associated with the request.
.IP "RQ_CLIENT_NAME (char *)"
The client host name.
.IP "RQ_CLIENT_ADDR (char *)"
A printable representation of the client network address.
.IP "RQ_CLIENT_SIN (struct sockaddr_in *)"
An internal representation of the client network address and port.  The
contents of the structure are not copied.
.IP "RQ_SERVER_NAME (char *)"
The hostname associated with the server endpoint address.
.IP "RQ_SERVER_ADDR (char *)"
A printable representation of the server endpoint address.
.IP "RQ_SERVER_SIN (struct sockaddr_in *)"
An internal representation of the server endpoint address and port.
The contents of the structure are not copied.
.IP "RQ_DAEMON (char *)"
The name of the daemon process running on the server host.
.IP "RQ_USER (char *)"
The name of the user on whose behalf the client host makes the request.
.PP
hosts_access() consults the access control tables described in the
\fIhosts_access(5)\fR manual page.  When internal endpoint information
is available, host names and client user names are looked up on demand,
using the request structure as a cache.  hosts_access() returns zero if
access should be denied.
.PP
hosts_ctl() is a wrapper around the request_init() and hosts_access()
routines with a perhaps more convenient interface (though it does not
pass on enough information to support automated client username
lookups).  The client host address, client host name and username
arguments should contain valid data or STRING_UNKNOWN.  hosts_ctl()
returns zero if access should be denied.
.PP
The \fIallow_severity\fR and \fIdeny_severity\fR variables determine
how accepted and rejected requests may be logged. They must be provided
by the caller and may be modified by rules in the access control
tables.
.SH DIAGNOSTICS
Problems are reported via the syslog daemon.
.SH SEE ALSO
hosts_access(5), format of the access control tables.
hosts_options(5), optional extensions to the base language.
.SH FILES
/etc/hosts.allow, /etc/hosts.deny, access control tables.
.SH BUGS
hosts_access() uses the strtok() library function. This may interfere
with other code that relies on strtok().
.SH AUTHOR
.na
.nf
Wietse Venema (wietse@wzv.win.tue.nl)
Department of Mathematics and Computing Science
Eindhoven University of Technology
Den Dolech 2, P.O. Box 513, 
5600 MB Eindhoven, The Netherlands
\" @(#) hosts_access.3 1.8 96/02/11 17:01:26
  415   17 Oct 2007 John M O'DonnellForumAdding MIDAS .root-files
The following program handles regular directories in a file, or folders (ugh).
Most histograms are added bin by bin.

For scaler events it is convenient to see the counts as a function of time (ala
sclaer history plots in mhttpd).  If the histogram looks like a scaler plot versus
time, then new bins are added on to the end (or into the middle!) of the histogram.

All different versions of cuts are kept.

TTrees are not explicitly supported, so probably don't do the right thing...

John.

> Dear MIDAS users,
> 
> I want to add several .root-files produced by the MIDAS analyzer, in a fast 
> and convenient way. ROOT's hadd fails because it does not know how to treat 
> TFolders. I guess this problem is not unique to me, so I hope that somebody of 
> you might already have found a solution.
> 
> Why don't I just run "analyzer -r 1 10000"?
> We have taken lots of runs under (rapidly) varying conditions, so it would be 
> lots of "-r". And the analysis is quite involved, so rerunning all data takes 
> about one hour on a fast PC making this quite painful.
> Therefore, I would like to rerun all data only once, and then add the result 
> files depending on different criteria.
> 
> Of course, I tried to write a script that does the adding. But somehow it is 
> incredibly slow. And I am not the Master Of C++, too.
> 
> Is there any deeper reason for MIDAS using TFolders, not TDirectorys? ROOT's 
> hadd can treat TDirectory. Can I simply patch "my" MIDAS? Is there general 
> interest in a change like this? (Does anyone have experience with the speed of 
> hadd?)
> 
> Looking forward to comments from the Forum.
> 
> Cheers,
> 
> Randolf
Attachment 1: histoAdd.cxx
#include <iostream>
#include <vector>
#include <iterator>
#include <cstring>
using namespace std;

#include "TROOT.h"
#include "TFile.h"
#include "TString.h"
#include "TDirectory.h"
#include "TObject.h"
#include "TClass.h"
#include "TKey.h"
#include "TH1.h"
#include "TAxis.h"
#include "TMath.h"
#include "TCutG.h"
#include "TFolder.h"

bool verbose (false);
TFolder *histosFolder (0);

//==============================================================================

void addObject (TObject *o, const TString &prefix, TFolder *opFolder=0);

/** called for each file to do the addition.
  * loops over each object in the file, and
  * uses addObject to dispatch the actuall addition.
  */

void add (TFile *file, const TString &prefix) {

//------------------------------------------------------------------------------

  TString dirName (file->GetName());
  if (verbose) cout << " scanning TFile" << endl;
  TString newPrefix (prefix + dirName + "/");

  TIter i (file->GetListOfKeys());
  while (TKey *k = static_cast<TKey *>( i())) {

    TObject *o (file->Get( k->GetName()));
    addObject( o, newPrefix);
  }

  return;
}

//==============================================================================

/** Most histograms are added bin by bin, but if simpleAdd == false,
  * the xaxis values are assumed different, in which case we look up
  * appropriate bin numbers, and use a new extended xaxis if needed.
  *
  * Use simpleAdd=false to accumulate scaler rate histograms.
  */
void add (const TH1 *newh, TH1 *&hsum, TFolder *opFolder) {

//------------------------------------------------------------------------------

  const bool simpleAdd (newh->GetXaxis()->GetTimeDisplay() ? false : true);

  if (!hsum) {
    hsum = (TH1 *)newh->Clone();
    TString title = "histoAdd: ";
    title += hsum->GetTitle();
    if (opFolder) hsum->SetDirectory( 0);
  }
  else if (simpleAdd) hsum->Add( newh);
  else { // extend axis - for 1D histos with equal sized bins

    size_t nBinsSum = hsum->GetNbinsX();
    size_t nBinsNew = newh->GetNbinsX();
    vector<Double_t>bin_contents;
    vector<Double_t>histo_edges;
    Int_t holder_bins;

    /* foundBin is either the overflow bin (if the 2 histograms don't overlap)
     * or it is the bin number in histoA that has the same low edge as the 
     * lowest bin edge in histoB. The only time that histograms can overlap 
     * is when the older scaler.cxx is used to create the histograms with 
     * fixed bin sizes. 
     */
    Int_t foundBin = hsum->FindBin( newh->GetBinLowEdge(1) );

    histo_edges.resize(foundBin);
    bin_contents.resize(foundBin);
    
    for( int i = 1; i <= foundBin; i++ ) {
      histo_edges[i-1] = hsum->GetBinLowEdge(i);
      bin_contents[i-1] = hsum->GetBinContent(i);
    }

    if(foundBin < nBinsSum)  { 
      //the histos overlap or we have already made holder bins
      holder_bins = 0;
    }
    else        {
      //create a "place holder" histo
      Int_t width = 10;
      holder_bins = (int)((newh->GetXaxis()->GetXmin() 
                    - hsum->GetXaxis()->GetXmax())/width);

      if( holder_bins < width ) holder_bins = width;

      TH1F *bin_holder = new TH1F("bin_holder", "bin_holder", holder_bins, 
                           hsum->GetXaxis()->GetXmax(), 
                           newh->GetXaxis()->GetXmin() );

      histo_edges.resize( foundBin + holder_bins );
      bin_contents.resize( foundBin + holder_bins );

      for( int i = 0; i < holder_bins; i++ )      {
        histo_edges[foundBin+i] = bin_holder->GetBinLowEdge(i+2);
        bin_contents[foundBin+i] = 0;
      }
      delete bin_holder;
    } //end else
  
    histo_edges.resize(  foundBin + holder_bins + nBinsNew+1 ); 
    bin_contents.resize( foundBin + holder_bins + nBinsNew+1 );

    for( int i = 0; i <= nBinsNew; i++ )   {
      histo_edges[i+foundBin+holder_bins] = newh->GetBinLowEdge(i+1);
      bin_contents[i+foundBin+holder_bins] = newh->GetBinContent(i+1);
    }

    hsum->SetBins( histo_edges.size()-1, &histo_edges[0] );

    for ( int i=1; i<histo_edges.size(); ++i) {
      hsum->SetBinContent( i, bin_contents[i-1]);
    }

    if (opFolder) {
      //opFolder->Remove( hsum);
      //opFolder->Add( exth);
      hsum->SetDirectory( 0);
    }
  }

  if (verbose) {
    if (simpleAdd) cout << " adding counts";
    else cout << " tagging on bins";
    cout << endl;
  }

  return;
}

//==============================================================================

/** Most cuts are written out just once, but if a cut is different from
  * the most recently written version of a cut with the same name, then
  * another copy of the cut is written out.  Thus if a cut changes during
  * a series of runs, all versions of the cut will be present in the
  * summed file.
  */
void add (const TCutG *o, TCutG *&oOut, TFolder *opFolder) {

//------------------------------------------------------------------------------

  const char *name (o->GetName());
  bool write (false);

  if (!oOut) write = true;
  else {

    Int_t n (o->GetN());
    if (n != oOut->GetN()) write = true;

    else {
      double x1, x2, y1, y2;
      for (Int_t i=0; i<n; ++i) {

        o   ->GetPoint( i, x1, y1);
        oOut->GetPoint( i, x2, y2);

        if ((x1 != x2) || (y1 != y2)) write = true;
      }
    }
  }

  if (write) {

    if (verbose) {
      if (oOut) cout << " changed";
      cout << " TCutG" << endl;
    }

    if (!opFolder) {

      oOut = const_cast<TCutG *>( o);
      o->Write( name, TObject::kSingleKey);

    } else {

      TCutG *clone = static_cast<TCutG *>( o->Clone());
      if (oOut) opFolder->Add( clone);
      oOut = clone;
    }
  } else if (verbose) cout << endl;

  return;
}

//==============================================================================

/** for most objects, we keep just the first version.
  */
void add (const TObject *o, TObject *&oSum, TFolder *opFolder) {

//------------------------------------------------------------------------------

  const char *name (o->GetName());

  if (!oSum) {
    if (verbose) cout << " saving TObject" << endl;
    if (!opFolder) o->Write( name, TObject::kSingleKey);
  } else {
    if (verbose) cout << endl;
  }

  return;
}

//==============================================================================

/** create the new directory and then start adding its contents
  */
void add (TDirectory *dir, TDirectory *&sumDir,
          TFolder *opFolder, const TString &prefix) {

//------------------------------------------------------------------------------

  TDirectory *currentDir (gDirectory);
  TString dirName (dir->GetName());
  if (verbose) cout << " scanning TDirectory" << endl;
  TString newPrefix (prefix + dirName + "/");

  if (!sumDir) sumDir = gDirectory->mkdir( dirName);
  sumDir->cd();

  TIter i (dir->GetListOfKeys());
  while (TKey *k = static_cast<TKey *>( i())) {

    TObject *o (dir->Get( k->GetName()));
    addObject( o, newPrefix, opFolder);
  }

  currentDir->cd();

  return;
}

//==============================================================================

/** create a new folder and then start adding its contents
  */
void add (const TFolder *folder, TFolder *&sumFolder,
          TFolder *parentFolder, const TString &prefix) {

//------------------------------------------------------------------------------

  if (verbose) cout << " scanning TFolder" << endl;
  const char *name (folder->GetName());
  TString newPrefix (prefix + name + "/");

  if (!sumFolder) sumFolder = new TFolder (name, name);
  if (!histosFolder) histosFolder = sumFolder;

  TIter i (folder->GetListOfFolders());
  while (TObject *o = i()) addObject( o, newPrefix, sumFolder);

  return;
}

//==============================================================================

int main (int argc, char **argv) {

//------------------------------------------------------------------------------

  if (argc < 3) {
    cerr << argv[0] << ": out_root_file in_root_file1 in_root_file2 ..." << endl;
    return 1;
  }

  TROOT root ("histoadd", "histoadd");
  root.SetBatch();

  TString opFileName (argv[1]);
  TFile *opFile (TFile::Open( opFileName, "RECREATE"));

  if (!opFile) {
    cerr << argv[0] << ": unable to open file: " << argv[1] << endl;
    return 1;
  }
  --argc;
  ++argv;
... 95 more lines ...
  1523   17 Apr 2019 John M O'DonnellInfoswitch of MIDAS to C++, how much C++?
some semi-random thoughts:

no templates strictly means you can't use std::string, std::vector etc.

printf is in any case part of C++ (#include <cstdio>), but std::ostreams can be faster (for std::cout, endl line causes buffer flushing, whereas "\n" does not flush the buffer but printf
always flushes the buffer), and formatting is possible (though very long winded).  printf does not allow to print things other than simple data, e.g. BANK_HEADER* bh; printf( "%?", *bh);

I've been writing all our DAQ code in C++ for a while now.

> > >
> > > With the removal of the requirement to make it possible to write MIDAS frontends in C, we can switch the MIDAS 
> > > default build to C++ and start using C++ features in the MIDAS API (std::string, std::vector, etc).
> > > 
> 
> C++ is a big animal. Obviously we want to use std::string, std::vector and similar improvements over plain C (we already use "//" for comments).
> 
> But in keeping with the Camel's nose fable (https://en.wikipedia.org/wiki/Camel%27s_nose), there are some parts of C++ we definitely do not want to use in MIDAS. Even the C++ FAQ talks 
> about "evil features", see https://isocpp.org/wiki/faq/big-picture#use-evil-things-sometimes
> 
> Here is my list of things to use and to avoid. Comments on this are very welcome - as everybody's experience with C++ is different (and everybody's experience is very valuable and very 
> welcome).
> 
> - std::string, std:vector, etc are in. I am already using them in the MIDAS API (midas.h)
> - extern "C" is out, everything has to be C++, will remove "extern "C"" from all midas header files.
> - exceptions are out, see https://stackoverflow.com/questions/1736146/why-is-exception-handling-bad
> - std::thread and std::mutex are in, at least for writing new frontends, but see discussion of "cannot use c++11". (maybe replace ss_mutex_xxx() with out own std::mutex look-alike).
> - heavy use of templates and heavy use of argument overloading is out - just by looking at the code, impossible to tell what function will be called
> - "auto" is on probation. I need to know if "auto v=f()" is an integer or a double when I write "auto w=v/2" or "auto w=v/2.0". see 
> https://softwareengineering.stackexchange.com/questions/180216/does-auto-make-c-code-harder-to-understand
> - unreadable gibberish is out (lambdas, etc)
> - C-style malloc()/free() is in. C++ new and delete are okey, but "delete[]" confuses me.
> - C-style printf() is in. C++ cout and "<<" gunk provide no way to easily format the output for easy reading.
> 
> K.O.
  436   18 Feb 2008 Jimmy NgaiBug ReportAnalyzer cannot run as Daemon
Hi All,

I'm testing MIDAS SVN rev-4113 on Scientific Linux 5.1 (i386) and the Analyzer 
can't start as Daemon. What I mean "can't" is that it stops running 
immediately without leaving any error messages. However, it can run offline or 
without becoming a Daemon. I have tested with ROOT 5.14e/5.16/5.18 and 
the "Experiment" example coming with MIDAS and this problem always happens. 
Any ideas?

Best Regards,
Jimmy
  485   05 Jun 2008 Jimmy NgaiForumCAEN VME-USE Bridge with MIDAS
Hi All,

Is there any example code for using MIDAS with the CAEN VME-USB Bridge V1718? 
Thanks.

Regards,
Jimmy
  486   07 Jun 2008 Jimmy NgaiForumCAEN VME-USE Bridge with MIDAS
Hi All,

I am testing the libraries provided by CAEN with the sample softwares in the 
bundle CD. The Windows sample program works fine, but I cannot get started with 
the Linux sample program. When I run CAENVMEDemo in Scientific Linux 5.1, it 
gives me a message "Error opening the device". I have followed the instructions 
in CAENVMElibReadme.txt: 
- compile and load the device driver v1718.ko
- install the library libCAENVME.so

Does anyone have any experience of using V1718 in Scientific Linux? Thanks.

Regards,
Jimmy


> Hi All,
> 
> Is there any example code for using MIDAS with the CAEN VME-USB Bridge V1718? 
> Thanks.
> 
> Regards,
> Jimmy
  493   01 Jul 2008 Jimmy NgaiForumCAEN V792N QDC with MIDAS
Dear All,

I have a problem when testing the V792N 16 CH QDC with the V1718 VME-USB 
Bridge on Scientific Linux 5.1 i386 (kernel 2.6.18-53.1.21.e15).

The problem is that the V792N does not response normally after a few minutes 
of continuous polling and readout of data. It seems like the V792N is hanged 
and a hardware reset of the VME system is required to bring it working again. 
If I do not poll for DREADY first and directly read the Output Buffer 
continuously, the system can work properly.

I have worked on this problem many days but I cannot find any clues to solve 
it. I have tried to use the CAENVMEDemo program (with some modifications) to 
do the same thing (polling and readout) and it works fine. CAEN technical 
support also doesn't know why the VME system is hanged. I think it might be a 
problem of MIDAS itself. I have tried with MIDAS revision 4132 and the trunk 
version, but the problem is still there. Is there any parameter in MIDAS 
(buffer size etc?) which may cause this problem? I have attached my frontend 
code and drivers for your reference.

Thank you for your kind attention.

Best Regards,
Jimmy
Attachment 1: frontend.c
/********************************************************************\

  Name:         frontend.c
  Created by:   Stefan Ritt
  Modified by:  Jimmy Ngai

  Date:         July 1, 2008

  Contents:     Experiment specific readout code (user part) of
                Midas frontend. This example simulates a "trigger
                event" which are filled with VME data. The trigger
                event is filled with two banks(ADC0 and TDC0).

  $Id: frontend.c 4089 2007-11-27 07:28:17Z ritt@PSI.CH $

\********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include "midas.h"
#include "mvmestd.h"
#include "experim.h"

#define HAVE_V792N

/* make frontend functions callable from the C framework */
#ifdef __cplusplus
extern "C" {
#endif

#ifdef HAVE_V792N
#include "vme/v792n.h"
#endif

/*-- Globals -------------------------------------------------------*/

/* The frontend name (client name) as seen by other MIDAS clients   */
char *frontend_name = "Sample Frontend";
/* The frontend file name, don't change it */
char *frontend_file_name = __FILE__;

/* frontend_loop is called periodically if this variable is TRUE    */
BOOL frontend_call_loop = FALSE;

/* a frontend status page is displayed with this frequency in ms */
INT display_period = 3000;

/* maximum event size produced by this frontend */
INT max_event_size = 10000;

/* maximum event size for fragmented events (EQ_FRAGMENTED) */
INT max_event_size_frag = 5 * 1024 * 1024;

/* buffer size to hold events */
INT event_buffer_size = 100 * 10000;

/* Hardware */
MVME_INTERFACE *myvme;

/* VME base address */
DWORD V792N_BASE = 0x32100000;

/* number of channels */
#define N_ADC      16

/*-- Function declarations -----------------------------------------*/

INT frontend_init();
INT frontend_exit();
INT begin_of_run(INT run_number, char *error);
INT end_of_run(INT run_number, char *error);
INT pause_run(INT run_number, char *error);
INT resume_run(INT run_number, char *error);
INT frontend_loop();

INT read_trigger_event(char *pevent, INT off);
INT read_scaler_event(char *pevent, INT off);

/*-- Equipment list ------------------------------------------------*/

EQUIPMENT equipment[] = {

   {"Trigger",               /* equipment name */
    {1, 0,                   /* event ID, trigger mask */
     "SYSTEM",               /* event buffer */
     EQ_POLLED,              /* equipment type */
     LAM_SOURCE(0, 0xFFFFFF),        /* event source crate 0, all stations */
     "MIDAS",                /* format */
     TRUE,                   /* enabled */
     RO_RUNNING,             /* read only when running */
     500,                    /* poll for 500ms */
     0,                      /* stop run after this event limit */
     0,                      /* number of sub events */
     0,                      /* don't log history */
     "", "", "",},
    read_trigger_event,      /* readout routine */
    },

   {""}
};

#ifdef __cplusplus
}
#endif

/********************************************************************\
              Callback routines for system transitions

  These routines are called whenever a system transition like start/
  stop of a run occurs. The routines are called on the following
  occations:

  frontend_init:  When the frontend program is started. This routine
                  should initialize the hardware.

  frontend_exit:  When the frontend program is shut down. Can be used
                  to releas any locked resources like memory, commu-
                  nications ports etc.

  begin_of_run:   When a new run is started. Clear scalers, open
                  rungates, etc.

  end_of_run:     Called on a request to stop a run. Can send
                  end-of-run event and close run gates.

  pause_run:      When a run is paused. Should disable trigger events.

  resume_run:     When a run is resumed. Should enable trigger events.
\********************************************************************/

INT init_vme_modules()
{
#ifdef HAVE_V792N
   v792n_SoftReset(myvme, V792N_BASE);
   v792n_Setup(myvme, V792N_BASE, 3);
//   v792n_Status(myvme, V792N_BASE);
#endif

   return SUCCESS;
}

/*-- Frontend Init -------------------------------------------------*/

INT frontend_init()
{
   int status;

   /* hardware initialization */

   // Open VME interface
   status = mvme_open(&myvme, 0);

   // Set am to A32 non-privileged Data
   mvme_set_am(myvme, MVME_AM_A32_ND);

   // Initialize all VME modules
   init_vme_modules();

   v792n_OfflineSet(myvme, V792N_BASE);
   v792n_DataClear(myvme, V792N_BASE);

   /* print message and return FE_ERR_HW if frontend should not be started */
   if (status != MVME_SUCCESS) {
      cm_msg(MERROR, "frontend_init", "VME interface could not be opened.");
//      return FE_ERR_HW;
   }

   return SUCCESS;
}

/*-- Frontend Exit -------------------------------------------------*/

INT frontend_exit()
{
   // Close VME interface
   mvme_close(myvme);

   return SUCCESS;
}

/*-- Begin of Run --------------------------------------------------*/

INT begin_of_run(INT run_number, char *error)
{
   // Initialize all VME modules
   init_vme_modules();

   v792n_OnlineSet(myvme, V792N_BASE);

   return SUCCESS;
}

/*-- End of Run ----------------------------------------------------*/

INT end_of_run(INT run_number, char *error)
{
   v792n_OfflineSet(myvme, V792N_BASE);
   v792n_DataClear(myvme, V792N_BASE);

   return SUCCESS;
}

/*-- Pause Run -----------------------------------------------------*/

INT pause_run(INT run_number, char *error)
{
   v792n_OfflineSet(myvme, V792N_BASE);

   return SUCCESS;
}

/*-- Resuem Run ----------------------------------------------------*/

INT resume_run(INT run_number, char *error)
{
   v792n_OnlineSet(myvme, V792N_BASE);

   return SUCCESS;
}

/*-- Frontend Loop -------------------------------------------------*/

INT frontend_loop()
{
   /* if frontend_call_loop is true, this routine gets called when
      the frontend is idle or once between every event */
   return SUCCESS;
}

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

/********************************************************************\

  Readout routines for different events

\********************************************************************/

/*-- Trigger event routines ----------------------------------------*/

INT poll_event(INT source, INT count, BOOL test)
/* Polling routine for events. Returns TRUE if event
   is available. If test equals TRUE, don't return. The test
   flag is used to time the polling */
{
   int i;
   DWORD lam;

   for (i = 0; i < count; i++) {
      lam = v792n_DataReady(myvme, V792N_BASE);
      if (lam)
         if (!test)
            return TRUE;
   }

   return FALSE;
}

/*-- Interrupt configuration ---------------------------------------*/

INT interrupt_configure(INT cmd, INT source, POINTER_T adr)
{
   switch (cmd) {
   case CMD_INTERRUPT_ENABLE:
      break;
   case CMD_INTERRUPT_DISABLE:
      break;
   case CMD_INTERRUPT_ATTACH:
      break;
   case CMD_INTERRUPT_DETACH:
      break;
   }
   return SUCCESS;
}

/*-- Event readout -------------------------------------------------*/

#ifdef HAVE_V792N
INT read_v792n(INT base, const char *bk_name, char *pevent, INT n_chn)
{
   INT i;
   INT nentry = 0, counter;
   DWORD data[V792N_MAX_CHANNELS+2];
   WORD *pdata;

   // Event counter
//   v792n_EvtCntRead(myvme, base, &counter);

   // Read event
   v792n_EventRead(myvme, base, data, &nentry);

   // Clear ADC
//   v792n_DataClear(myvme, base);

   // Create ADC bank
   bk_create(pevent, bk_name, TID_WORD, &pdata);

   for (i = 0; i < n_chn; i++)
      pdata[i] = 0;

   for (i = 0; i < nentry; i++) {
... 27 more lines ...
Attachment 2: v1718.c
/********************************************************************

  Name:         v1718.c
  Created by:   Jimmy Ngai

  Contents:     Midas VME standard (MVMESTD) layer for CAEN V1718
                VME-USB2.0 Bridge using CAENVMElib Linux library

  Based on sis3100.c by Stefan Ritt

  $Id: $

\********************************************************************/

#ifdef __linux__
#ifndef OS_LINUX
#define OS_LINUX
#endif
#endif

#ifdef OS_LINUX

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>

#include "CAENVMElib.h"

#endif // OS_LINUX

#include "mvmestd.h"

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

int mvme_open(MVME_INTERFACE **vme, int idx)
{
   *vme = (MVME_INTERFACE *) malloc(sizeof(MVME_INTERFACE));
   if (*vme == NULL)
      return MVME_NO_MEM;

   memset(*vme, 0, sizeof(MVME_INTERFACE));

   /* open VME */
   if (CAENVME_Init(cvV1718, 0, idx, &(*vme)->handle) != cvSuccess)
      return MVME_NO_INTERFACE;

   /* default values */
   (*vme)->am        = MVME_AM_DEFAULT;
   (*vme)->dmode     = MVME_DMODE_D32;
   (*vme)->blt_mode  = MVME_BLT_NONE;
   (*vme)->table     = NULL; // not used

   return MVME_SUCCESS;
}

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

int mvme_close(MVME_INTERFACE *vme)
{
   CAENVME_End(vme->handle);

   return MVME_SUCCESS;
}

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

int mvme_sysreset(MVME_INTERFACE *vme)
{
   CAENVME_SystemReset(vme->handle);

   return MVME_SUCCESS;
}

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

int mvme_write(MVME_INTERFACE *vme, mvme_addr_t vme_addr, void *src, mvme_size_t n_bytes)
{
   mvme_size_t n;
   DWORD data;
   int status=0;
   int hvme;
   hvme = vme->handle;

   if (n_bytes <= 4) {
      data = n = 0;
      memcpy(&data, src, n_bytes);

      /* D8 */
      if (vme->dmode == MVME_DMODE_D8)
         status = CAENVME_WriteCycle(hvme, vme_addr, &data, vme->am, cvD8);
      /* D16 */
      else if (vme->dmode == MVME_DMODE_D16)
         status = CAENVME_WriteCycle(hvme, vme_addr, &data, vme->am, cvD16);
      /* D32 */
      else if (vme->dmode == MVME_DMODE_D32)
         status = CAENVME_WriteCycle(hvme, vme_addr, &data, vme->am, cvD32);
      
      if (status == cvSuccess)
         n = n_bytes;
      else
         n = 0;
   } else {

      /* D32 BLT */
      if (vme->blt_mode == MVME_BLT_BLT32)
         status |= CAENVME_BLTWriteCycle(hvme, vme_addr, src, n_bytes, vme->am, cvD32, &n);
      /* D64 MBLT */
      else if (vme->blt_mode == MVME_BLT_MBLT64)
         status |= CAENVME_MBLTWriteCycle(hvme, vme_addr, src, n_bytes, vme->am, &n);

      if (status != cvSuccess)
         n = 0;
   }

   return n;
}

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

int mvme_write_value(MVME_INTERFACE *vme, mvme_addr_t vme_addr, unsigned int value)
{
   mvme_size_t n;
   int status=0;
   int hvme;
   hvme = vme->handle;

   if (vme->dmode == MVME_DMODE_D8)
      n = 1;
   else if (vme->dmode == MVME_DMODE_D16)
      n = 2;
   else
      n = 4;

   /* D8 */
   if (vme->dmode == MVME_DMODE_D8)
      status = CAENVME_WriteCycle(hvme, vme_addr, &value, vme->am, cvD8);
   /* D16 */
   else if (vme->dmode == MVME_DMODE_D16)
      status = CAENVME_WriteCycle(hvme, vme_addr, &value, vme->am, cvD16);
   /* D32 */
   else if (vme->dmode == MVME_DMODE_D32)
      status = CAENVME_WriteCycle(hvme, vme_addr, &value, vme->am, cvD32);

   if (status != cvSuccess)
      n = 0;

   return n;
}

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

int mvme_read(MVME_INTERFACE *vme, void *dst, mvme_addr_t vme_addr, mvme_size_t n_bytes)
{
   mvme_size_t i, n;
   DWORD data;
   int status=0, cfifo;
   int hvme;
   hvme = vme->handle;

   if (n_bytes <= 4) {
      data = 0;

      /* D8 */
      if (vme->dmode == MVME_DMODE_D8)
         status = CAENVME_ReadCycle(hvme, vme_addr, &data, vme->am, cvD8);
      /* D16 */
      else if (vme->dmode == MVME_DMODE_D16)
         status = CAENVME_ReadCycle(hvme, vme_addr, &data, vme->am, cvD16);
      /* D32 */
      else if (vme->dmode == MVME_DMODE_D32)
         status = CAENVME_ReadCycle(hvme, vme_addr, &data, vme->am, cvD32);
      
      memcpy(dst, &data, n_bytes);
      if (status == cvSuccess)
         n = n_bytes;
      else
         n = 0;

   } else {

      n = 0;

      /* normal I/O */
      if (vme->blt_mode == MVME_BLT_NONE) {
         for (i=0 ; i<n_bytes ; i++)
            status = CAENVME_ReadCycle(hvme, vme_addr, dst+i, vme->am, cvD8);
         n = n_bytes;
      /* D32 BLT */
      } else if (vme->blt_mode == MVME_BLT_BLT32)
         status |= CAENVME_BLTReadCycle(hvme, vme_addr, dst, n_bytes, vme->am, cvD32, &n);
      /* D32 FIFO BLT */
      else if (vme->blt_mode == MVME_BLT_BLT32FIFO) {
         CAENVME_GetFIFOMode(hvme, &cfifo);
         status = CAENVME_SetFIFOMode(hvme, 1);
         status |= CAENVME_BLTReadCycle(hvme, vme_addr, dst, n_bytes, vme->am, cvD32, &n);
         CAENVME_SetFIFOMode(hvme, cfifo);
      /* D64 MBLT */
      } else if (vme->blt_mode == MVME_BLT_MBLT64)
         status |= CAENVME_MBLTReadCycle(hvme, vme_addr, dst, n_bytes, vme->am, &n);
      /* D64 FIFO MBLT */
      else if (vme->blt_mode == MVME_BLT_MBLT64FIFO) {
         CAENVME_GetFIFOMode(hvme, &cfifo);
         status = CAENVME_SetFIFOMode(hvme, 1);
         status |= CAENVME_MBLTReadCycle(hvme, vme_addr, dst, n_bytes, vme->am, &n);
         CAENVME_SetFIFOMode(hvme, cfifo);
      }

      if (status != cvSuccess)
         n = 0;
   }

   return n;
}

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

unsigned int mvme_read_value(MVME_INTERFACE *vme, mvme_addr_t vme_addr)
{
   unsigned int data;
   int status=0;
   int hvme;
   hvme = vme->handle;

   data = 0;

   /* D8 */
   if (vme->dmode == MVME_DMODE_D8)
      status = CAENVME_ReadCycle(hvme, vme_addr, &data, vme->am, cvD8);
   /* D16 */
   else if (vme->dmode == MVME_DMODE_D16)
      status = CAENVME_ReadCycle(hvme, vme_addr, &data, vme->am, cvD16);
   /* D32 */
   else if (vme->dmode == MVME_DMODE_D32)
      status = CAENVME_ReadCycle(hvme, vme_addr, &data, vme->am, cvD32);

   return data;
}

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

int mvme_set_am(MVME_INTERFACE *vme, int am)
{
   vme->am = am;
   return MVME_SUCCESS;
}

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

int mvme_get_am(MVME_INTERFACE *vme, int *am)
{
   *am = vme->am;
   return MVME_SUCCESS;
}

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

int mvme_set_dmode(MVME_INTERFACE *vme, int dmode)
{
   vme->dmode = dmode;
   return MVME_SUCCESS;
}

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

int mvme_get_dmode(MVME_INTERFACE *vme, int *dmode)
{
   *dmode = vme->dmode;
   return MVME_SUCCESS;
}

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

int mvme_set_blt(MVME_INTERFACE *vme, int mode)
{
   vme->blt_mode = mode;
   return MVME_SUCCESS;
}

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

int mvme_get_blt(MVME_INTERFACE *vme, int *mode)
{
   *mode = vme->blt_mode;
   return MVME_SUCCESS;
}
Attachment 3: v792n.h
/*********************************************************************

  Name:         v792n.h
  Created by:   Jimmy Ngai

  Contents:     V792N 16ch. QDC include

  Based on v792.h by Pierre-Andre Amaudruz

  $Id: $
*********************************************************************/
#ifndef  V792N_INCLUDE_H
#define  V792N_INCLUDE_H

#include <stdio.h>
#include <string.h>
#include "mvmestd.h"

#ifdef __cplusplus
extern "C" {
#endif

#define  V792N_MAX_CHANNELS       (DWORD) 16
#define  V792N_REG_BASE           (DWORD) (0x1000)
#define  V792N_FIRM_REV           (DWORD) (0x1000)
#define  V792N_GEO_ADDR_RW        (DWORD) (0x1002)
#define  V792N_MCST_CBLT_RW       (DWORD) (0x1004)
#define  V792N_BIT_SET1_RW        (DWORD) (0x1006)
#define  V792N_BIT_CLEAR1_WO      (DWORD) (0x1008)
#define  V792N_SOFT_RESET         (DWORD) (0x1<<7)
#define  V792N_INT_LEVEL_WO       (DWORD) (0x100A)
#define  V792N_INT_VECTOR_WO      (DWORD) (0x100C)
#define  V792N_CSR1_RO            (DWORD) (0x100E)
#define  V792N_CR1_RW             (DWORD) (0x1010)
#define  V792N_ADER_H_RW          (DWORD) (0x1012)
#define  V792N_ADER_L_RW          (DWORD) (0x1014)
#define  V792N_SINGLE_RST_WO      (DWORD) (0x1016)
#define  V792N_MCST_CBLT_CTRL_RW  (DWORD) (0x101A)
#define  V792N_EVTRIG_REG_RW      (DWORD) (0x1020)
#define  V792N_CSR2_RO            (DWORD) (0x1022)
#define  V792N_EVT_CNT_L_RO       (DWORD) (0x1024)
#define  V792N_EVT_CNT_H_RO       (DWORD) (0x1026)
#define  V792N_INCR_EVT_WO        (DWORD) (0x1028)
#define  V792N_INCR_OFFSET_WO     (DWORD) (0x102A)
#define  V792N_LD_TEST_RW         (DWORD) (0x102C)
#define  V792N_DELAY_CLEAR_RW     (DWORD) (0x102E)
#define  V792N_FCLR_WIN_RW        (DWORD) (0x102E)
#define  V792N_BIT_SET2_RW        (DWORD) (0x1032)
#define  V792N_BIT_CLEAR2_WO      (DWORD) (0x1034)
#define  V792N_W_MEM_TEST_WO      (DWORD) (0x1036)
#define  V792N_MEM_TEST_WORD_H_WO (DWORD) (0x1038)
#define  V792N_MEM_TEST_WORD_L_WO (DWORD) (0x103A)
#define  V792N_CRATE_SEL_RW       (DWORD) (0x103C)
#define  V792N_TEST_EVENT_WO      (DWORD) (0x103E)
#define  V792N_EVT_CNT_RST_WO     (DWORD) (0x1040)
#define  V792N_IPED_RW            (DWORD) (0x1060)
#define  V792N_R_MEM_TEST_WO      (DWORD) (0x1064)
#define  V792N_SWCOMM_WO          (DWORD) (0x1068)
#define  V792N_SLIDECONST_RW      (DWORD) (0x106A)
#define  V792N_AAD_RO             (DWORD) (0x1070)
#define  V792N_BAD_RO             (DWORD) (0x1072)
#define  V792N_THRES_BASE         (DWORD) (0x1080)

WORD v792n_Read16(MVME_INTERFACE *mvme, DWORD base, int offset);
void v792n_Write16(MVME_INTERFACE *mvme, DWORD base, int offset, WORD value);
DWORD v792n_Read32(MVME_INTERFACE *mvme, DWORD base, int offset);
void v792n_Write32(MVME_INTERFACE *mvme, DWORD base, int offset, DWORD value);

int  v792n_DataReady(MVME_INTERFACE *mvme, DWORD base);
int  v792n_isEvtReady(MVME_INTERFACE *mvme, DWORD base);
int  v792n_isBusy(MVME_INTERFACE *mvme, DWORD base);
int  v792n_EventRead(MVME_INTERFACE *mvme, DWORD base, DWORD *pdest, int *nentry);
int  v792n_DataRead(MVME_INTERFACE *mvme, DWORD base, DWORD *pdest, int *nentry);
void v792n_DataClear(MVME_INTERFACE *mvme, DWORD base);
void v792n_EvtCntRead(MVME_INTERFACE *mvme, DWORD base, DWORD *evtcnt);
void v792n_EvtCntReset(MVME_INTERFACE *mvme, DWORD base);
void v792n_IntSet(MVME_INTERFACE *mvme, DWORD base, int level, int vector);
void v792n_IntEnable(MVME_INTERFACE *mvme, DWORD base, int level);
void v792n_IntDisable(MVME_INTERFACE *mvme, DWORD base);
void v792n_EvtTriggerSet(MVME_INTERFACE *mvme, DWORD base, int count);
void v792n_SingleShotReset(MVME_INTERFACE *mvme, DWORD base);
void v792n_SoftReset(MVME_INTERFACE *mvme, DWORD base);
void v792n_Trigger(MVME_INTERFACE *mvme, DWORD base);
int  v792n_ThresholdRead(MVME_INTERFACE *mvme, DWORD base, WORD *threshold);
int  v792n_ThresholdWrite(MVME_INTERFACE *mvme, DWORD base, WORD *threshold);
int  v792n_CSR1Read(MVME_INTERFACE *mvme, DWORD base);
int  v792n_CSR2Read(MVME_INTERFACE *mvme, DWORD base);
int  v792n_BitSet2Read(MVME_INTERFACE *mvme, DWORD base);
void v792n_BitSet2Set(MVME_INTERFACE *mvme, DWORD base, WORD pat);
void v792n_BitSet2Clear(MVME_INTERFACE *mvme, DWORD base, WORD pat);
WORD v792n_ControlRegister1Read(MVME_INTERFACE *mvme, DWORD base);
void v792n_ControlRegister1Write(MVME_INTERFACE *mvme, DWORD base, WORD pat);
void v792n_OnlineSet(MVME_INTERFACE *mvme, DWORD base);
void v792n_OfflineSet(MVME_INTERFACE *mvme, DWORD base);
void v792n_BlkEndEnable(MVME_INTERFACE *mvme, DWORD base);
void v792n_OverRangeEnable(MVME_INTERFACE *mvme, DWORD base);
void v792n_OverRangeDisable(MVME_INTERFACE *mvme, DWORD base);
void v792n_LowThEnable(MVME_INTERFACE *mvme, DWORD base);
void v792n_LowThDisable(MVME_INTERFACE *mvme, DWORD base);
void v792n_EmptyEnable(MVME_INTERFACE *mvme, DWORD base);
void v792n_CrateSet(MVME_INTERFACE *mvme, DWORD base, DWORD *evtcnt);
void v792n_DelayClearSet(MVME_INTERFACE *mvme, DWORD base, int delay);
int  v792n_Setup(MVME_INTERFACE *mvme, DWORD base, int mode);
void v792n_Status(MVME_INTERFACE *mvme, DWORD base);
int  v792n_isPresent(MVME_INTERFACE *mvme, DWORD base);

  enum v792n_DataType {
    v792n_typeMeasurement=0,
    v792n_typeHeader     =2,
    v792n_typeFooter     =4,
    v792n_typeFiller     =6
  };

  typedef union {
    DWORD raw;
    struct v792n_Entry {
      unsigned adc:12; // bit0 here
      unsigned ov:1;
      unsigned un:1;
      unsigned _pad_1:3;
      unsigned channel:4;
      unsigned _pad_2:3;
      unsigned type:3;
      unsigned geo:5;
    } data ;
    struct v792n_Header {
      unsigned _pad_1:8; // bit0 here
      unsigned cnt:6;
      unsigned _pad_2:2;
      unsigned crate:8;
      unsigned type:3;
      unsigned geo:5;
    } header;
    struct v792n_Footer {
      unsigned evtCnt:24; // bit0 here
      unsigned type:3;
      unsigned geo:5;
    } footer;
  } v792n_Data;

  typedef union {
    DWORD raw;
    struct {
      unsigned DataReady:1; // bit0 here
      unsigned GlobalDataReady:1;
      unsigned Busy:1;
      unsigned GlobalBusy:1;
      unsigned Amnesia:1;
      unsigned Purge:1;
      unsigned TermOn:1;
      unsigned TermOff:1;
      unsigned EventReady:1; //bit 8 here
    };
  } v792n_StatusRegister1;
  typedef union {
    DWORD raw;
    struct {
      unsigned _pad_1:1; // bit0 here
      unsigned BufferEmpty:1;
      unsigned BufferFull:1;
      unsigned _pad_2:1;
      unsigned PB:4;
      //unsigned DSEL0:1;
      //unsigned DSEL1:1;
      //unsigned CSEL0:1;
      //unsigned CSEL1:1;
    };
  } v792n_StatusRegister2;
  typedef union {
    DWORD raw;
    struct {
      unsigned _pad_1:2;
      unsigned BlkEnd:1;
      unsigned _pad_2:1;
      unsigned ProgReset:1;
      unsigned BErr:1;
      unsigned Align64:1;
    };
  } v792n_ControlRegister1;
  typedef union {
    DWORD raw;
    struct {
      unsigned MemTest:1;
      unsigned OffLine:1;
      unsigned ClearData:1;
      unsigned OverRange:1;
      unsigned LowThresh:1;
      unsigned _pad_1:1;//bit5
      unsigned TestAcq:1;
      unsigned SLDEnable:1;
      unsigned StepTH:1;
      unsigned _pad_2:2;//bits 9-10
      unsigned AutoIncr:1;
      unsigned EmptyProg:1;
      unsigned SlideSubEnable:1;
      unsigned AllTrg:1;
    };
  } v792n_BitSet2Register;

  void v792n_printEntry(const v792n_Data* v);

#ifdef __cplusplus
}
#endif

#endif // V792N_INCLUDE_H

/* emacs
 * Local Variables:
 * mode:C
 * mode:font-lock
 * tab-width: 8
 * c-basic-offset: 2
 * End:
 */
Attachment 4: v792n.c
/*********************************************************************

  Name:         v792n.c
  Created by:   Jimmy Ngai

  Contents:     V792N 16ch. QDC

  Based on v792.c by Pierre-Andre Amaudruz
                
  $Id: $
*********************************************************************/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#if defined(OS_LINUX)
#include <unistd.h>
#endif
#include "v792n.h"

WORD v792n_Read16(MVME_INTERFACE *mvme, DWORD base, int offset)
{
  int cmode;
  WORD data;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  data = mvme_read_value(mvme, base+offset);
  mvme_set_dmode(mvme, cmode);
  return data;
}

void v792n_Write16(MVME_INTERFACE *mvme, DWORD base, int offset, WORD value)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+offset, value);
  mvme_set_dmode(mvme, cmode);
}

DWORD v792n_Read32(MVME_INTERFACE *mvme, DWORD base, int offset)
{
  int cmode;
  DWORD data;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D32);
  data = mvme_read_value(mvme, base+offset);
  mvme_set_dmode(mvme, cmode);
  return data;
}

void v792n_Write32(MVME_INTERFACE *mvme, DWORD base, int offset, DWORD value)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D32);
  mvme_write_value(mvme, base+offset, value);
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
int v792n_DataReady(MVME_INTERFACE *mvme, DWORD base)
{
  int data_ready, cmode;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  data_ready = mvme_read_value(mvme, base+V792N_CSR1_RO) & 0x1;
  mvme_set_dmode(mvme, cmode);
  return data_ready;
}

/*****************************************************************/
int v792n_isEvtReady(MVME_INTERFACE *mvme, DWORD base)
{
  int csr;
  csr = v792n_CSR1Read(mvme, base);
  return (csr & 0x100);
}

/*****************************************************************/
int v792n_isBusy(MVME_INTERFACE *mvme, DWORD base)
{
  int status, busy, timeout, cmode;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  timeout = 1000;
  do {
    status = mvme_read_value(mvme, base+V792N_CSR1_RO);
    busy = status & 0x4;
    timeout--;
  } while (busy || timeout);
  mvme_set_dmode(mvme, cmode);
  return (busy != 0 ? 1 : 0);
}

/*****************************************************************/
/*
Read single event, return event length (number of entries)
Uses single vme access! (1us/D32)
*/
int v792n_EventRead(MVME_INTERFACE *mvme, DWORD base, DWORD *pdest, int *nentry)
{
#define USE_BLT_READ_2

#ifdef USE_SINGLE_READ
  DWORD hdata;
  int   cmode;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D32);

  *nentry = 0;
  if (v792n_DataReady(mvme, base)) {
    do {
      hdata = mvme_read_value(mvme, base);
    } while (!(hdata & 0x02000000)); // skip up to the header

    pdest[*nentry] = hdata;
    *nentry += 1;
    do {
      pdest[*nentry] = mvme_read_value(mvme, base);
      *nentry += 1;
    } while (!(pdest[*nentry-1] & 0x04000000)); // copy until the trailer

    nentry--;
  }

  mvme_set_dmode(mvme, cmode);
#endif // USE_SINGLE_READ

#ifdef USE_BLT_READ_1
  DWORD hdata, data[V792N_MAX_CHANNELS+2];
  int   cam, cmode, cnt, i;

  mvme_get_am(mvme, &cam);
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D32);

  *nentry = 0;
  if (v792n_DataReady(mvme, base)) {
    do {
      hdata = mvme_read_value(mvme, base);
    } while (!(hdata & 0x02000000)); // skip up to the header

    mvme_set_am(mvme, MVME_AM_A32_NB);
    mvme->blt_mode = MVME_BLT_BLT32;
    cnt = (hdata >> 8) & 0x3F;

    mvme_read(mvme, data, base, (cnt+1)*4);
    pdest[0] = hdata;
    for (i=1;i<=cnt+1;i++)
      pdest[i] = data[i-1];

    *nentry = cnt + 2;
  }

  mvme_set_am(mvme, cam);
  mvme_set_dmode(mvme, cmode);
#endif // USE_BLT_READ_1

#ifdef USE_BLT_READ_2
  DWORD hdata;
  int   cam, cmode, cnt;

  mvme_get_am(mvme, &cam);
  mvme_get_dmode(mvme, &cmode);

  *nentry = 0;
//  if (v792n_DataReady(mvme, base)) {
    mvme_set_am(mvme, MVME_AM_A32_NB);
    mvme->blt_mode = MVME_BLT_BLT32;
    mvme_read(mvme, pdest, base, (V792N_MAX_CHANNELS+2)*4);
    cnt = (pdest[0] >> 8) & 0x3F;
    *nentry = cnt + 2;
//  }

  mvme_set_am(mvme, cam);
  mvme_set_dmode(mvme, cmode);
#endif //USE_BLT_READ_2

  return *nentry;
}

/*****************************************************************/
/*
Read nentry of data from the data buffer. Will use the DMA engine
if size is larger than 127 bytes.
*/
int v792n_DataRead(MVME_INTERFACE *mvme, DWORD base, DWORD *pdest, int *nentry)
{
  int  cmode;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D32);
//  *nentry = 128;
  if (v792n_DataReady(mvme, base)) {
    mvme_read(mvme, pdest, base, *nentry*4);
  }
  mvme_set_dmode(mvme, cmode);
  return *nentry;
}

/*****************************************************************/
void v792n_DataClear(MVME_INTERFACE *mvme, DWORD base)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_BIT_SET2_RW, 0x4);
  mvme_write_value(mvme, base+V792N_BIT_CLEAR2_WO, 0x4);
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_EvtCntRead(MVME_INTERFACE *mvme, DWORD base, DWORD *evtcnt)
{
  int cmode;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  *evtcnt  = mvme_read_value(mvme, base+V792N_EVT_CNT_L_RO);
  *evtcnt += (mvme_read_value(mvme, base+V792N_EVT_CNT_H_RO) << 16);
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_EvtCntReset(MVME_INTERFACE *mvme, DWORD base)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_EVT_CNT_RST_WO, 1);
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_IntSet(MVME_INTERFACE *mvme, DWORD base, int level, int vector)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_INT_VECTOR_WO, (vector & 0xFF));
  mvme_write_value(mvme, base+V792N_INT_LEVEL_WO, (level & 0x7));
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_IntEnable(MVME_INTERFACE *mvme, DWORD base, int level)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_EVTRIG_REG_RW, (level & 0x1F));
  /* Use the trigger buffer for int enable/disable
  mvme_write_value(mvme, base+V792N_INT_LEVEL_WO, (level & 0x7));
  */
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_IntDisable(MVME_INTERFACE *mvme, DWORD base)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_EVTRIG_REG_RW, 0);
  /* Use the trigger buffer for int enable/disable
     Setting a level 0 reboot the VMIC !
  mvme_write_value(mvme, base+V792N_INT_LEVEL_WO, 0);
  */
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_EvtTriggerSet(MVME_INTERFACE *mvme, DWORD base, int count)
{
  int cmode;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_EVTRIG_REG_RW, (count & 0x1F));
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_SingleShotReset(MVME_INTERFACE *mvme, DWORD base)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_SINGLE_RST_WO, 1);
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_SoftReset(MVME_INTERFACE *mvme, DWORD base)
{
... 407 more lines ...
  528   20 Nov 2008 Jimmy NgaiInfoRecommended platform for running MIDAS
Dear All,

Is there any recommended platforms for running MIDAS? Have anyone encountered 
problems when running MIDAS on Scientific Linux?

Thanks.

Jimmy
  530   26 Nov 2008 Jimmy NgaiInfoSend email alert in alarm system
Dear All,

We have a temperature/humidity sensor in MIDAS now and will add a liquid level 
sensor to MIDAS soon. We want the operators to get alerted ASAP when the 
laboratory environment or the liquid level reached some critical levels. Can 
MIDAS send email alerts or SMS alerts to cell phones when the alarms are 
triggered? If yes, how can I config it?

Many thanks!

Best Regards,
Jimmy
  541   12 Dec 2008 Jimmy NgaiInfoCustom page which executes custom function
Dear All,

How can I add a button at the top of the "Status" webpage which will show a 
page similar to the "CNAF" one after I click on it? and how can I make a 
custom page similar to "CNAF" which allow me to call some custom funtions? I 
want to make a page which is particularly for doing calibration.

Thank you for your attention!

Best Regards,
Jimmy Ngai
  565   17 Apr 2009 Jimmy NgaiForumMIDAS mhttpd custom page questions
Dear All,

I have created a custom page (please see the attachment) and imported into 
MIDAS with key name "Control panel&" (without the ""). I have the following 
two questions:

1) I display the status of the run with <odb src="/Runinfo/State">, but it 
returns numbers which is not user friendly. How can I make something 
like "Running" with green background and "Stopped" with red background in the 
default status page?

2) When I click either Start/Stop/Pause/Resume, it can performs the right 
things, but afterward it jumps to the page "http://domain.name:8081/CS/" which 
shows "Invalid custom page: NULL path". How can I make it returns to the 
correct page "http://domain.name:8081/CS/Control%20panel"?

Thank you for your attention.

Best Regards,
Jimmy
Attachment 1: control_panel.html
  566   20 Apr 2009 Jimmy NgaiForumMIDAS mhttpd custom page questions
Dear All,

I have one more question. I use <odb src="odb field" edit=1> to display an 
editable ODB value, but how can I show this value in hexadecimal?

Thanks.

Best Regards,
Jimmy


> Dear All,
> 
> I have created a custom page (please see the attachment) and imported into 
> MIDAS with key name "Control panel&" (without the ""). I have the following 
> two questions:
> 
> 1) I display the status of the run with <odb src="/Runinfo/State">, but it 
> returns numbers which is not user friendly. How can I make something 
> like "Running" with green background and "Stopped" with red background in the 
> default status page?
> 
> 2) When I click either Start/Stop/Pause/Resume, it can performs the right 
> things, but afterward it jumps to the page "http://domain.name:8081/CS/" which 
> shows "Invalid custom page: NULL path". How can I make it returns to the 
> correct page "http://domain.name:8081/CS/Control%20panel"?
> 
> Thank you for your attention.
> 
> Best Regards,
> Jimmy
  594   15 Jun 2009 Jimmy NgaiForumTime limit of each run
Dear All,

Can one set a time limit for each run? I can only find event limit in ODB. 
Thanks.

Jimmy
  624   01 Sep 2009 Jimmy NgaiForumTimeout during run transition
Dear All,

I'm using SL5 and MIDAS rev 4528. Occasionally, when I stop a run in odbedit, 
a timeout would occur: 
[midas.c:9496:rpc_client_call,ERROR] rpc timeout after 121 sec, routine 
= "rc_transition", host = "computerB", connection closed
Error: Unknown error 504 from client 'Frontend' on host computerB

This error seems to be random without any reason or pattern. After this error 
occurs, I cannot start or stop any run. Sometime restarting MIDAS can bring 
the system working again, but sometime not.

Another transition timeout occurs after I change any ODB value using the web 
interface:
[midas.c:8291:rpc_client_connect,ERROR] timeout on receive remote computer 
info: 
[midas.c:3642:cm_transition,ERROR] cannot connect to client "Frontend" on host 
computerB, port 36255, status 503
Error: Cannot connect to client 'Frontend'

This error is reproducible: start run -> change ODB value within webpage -> 
stop run -> timeout!

Any idea?

Thanks,
Jimmy
ELOG V3.1.4-2e1708b5