Back Midas Rome Roody Rootana
  Midas DAQ System, Page 133 of 137  Not logged in ELOG logo
New entries since:Wed Dec 31 16:00:00 1969
ID Date Author Topic Subjectdown
  1192   23 Aug 2016 Stefan RittForumAlarm/Warning
> Midas has a nice alarm system. I am wondering whether it is easily possible to
> get the Alarm/Warning banner also on top of custom pages?!

K.O. made nice JavaScript routines to access the alarm status. The new alarm page is completely 
made dynamically from JavaScript code (mhttpd does not supply any HTML code any more, only 
functions to obtain ODB values etc). Part of this new dynamic page must be some code to display 
the alarm status. You just need to copy this to your custom page. K.O. can tell you details.

Stefan
  1206   30 Sep 2016 Konstantin OlchanskiForumAlarm/Warning
> > Midas has a nice alarm system. I am wondering whether it is easily possible to
> > get the Alarm/Warning banner also on top of custom pages?!
> 
> K.O. made nice JavaScript routines to access the alarm status. The new alarm page is completely 
> made dynamically from JavaScript code (mhttpd does not supply any HTML code any more, only 
> functions to obtain ODB values etc). Part of this new dynamic page must be some code to display 
> the alarm status. You just need to copy this to your custom page. K.O. can tell you details.
> 

Yes, please look at resources/alarm.html and the "get_alarms" JSON-RPC method. The "get_alarms" example in 
resources/example.html probably already does exactly what you need. Also note the presence of "al_reset_alarm" and 
"al_trigger_alarm" JSON_RPC methods.

K.O.
  2411   19 Jun 2022 Francesco RengaForumAlarm on variable not updating
Dear all,
I've an ODB equipment that sometimes loses the connection with the hardware, so that the variables are not updated anymore. The connection can be restored by restarting the frontend. It would be useful to have an alarm based on the time from the last update of some variable (i.e. the alarm is triggered if the variable is not updated for more than X seconds). Is there a method to implement such an alarm in MIDAS?

Thank you very much,
Francesco
  2413   20 Jun 2022 Stefan RittForumAlarm on variable not updating
There are two functions to do that, one check the last write access, the other the last write access if the run is running. The alarm condition looks like:

access(/Equipment/.../Variables/Input[10]) > 60

which will cause an alarm if the Input[10] is not written for more than 60 seconds. The other function which checks the run status as well is like:

access_running(...odb key...) > 60

You can actually see an example on the MEG alarm page.

Rather than having an alarm for that I would however recommend that you program you frontend such that it realizes if it looses connections, then tries automatically to reconnect or trigger an alarm itself (so-called "internal" alarm). This is also how the MSCB system is working and is much more robust.

Stefan
  2   11 Aug 2003 Konstantin Olchanski Alarm on no ping?
I want midas alarms to go off when I cannot ping arbitrary remote hosts. Is
there is easy/preferred way to do this? K.O.
  4   18 Dec 2003 Stefan Ritt Alarm on no ping?
> I want midas alarms to go off when I cannot ping arbitrary remote hosts. Is
> there is easy/preferred way to do this? K.O.

There are "internal alarms" with type AT_EVALUATED. Just find a program 
where you can put some code which gets periodically executed (like the idle 
loop in the frontend), and so something like:

DWORD last = 0;

  if (ss_time() > last+60)
    {
    last = ss_time();

    /* do a ping via socket(), bind() and connect() */
    ...

    if (status != CM_SUCCESS)
      al_trigger_alarm("XYZ Ping", str, "Warning", 
                       "Host is dead", AT_INTERNAL);
    }

Pierre does the same thing in lazylogger.c, just have a look. I don't know 
how to do a ping correctly in C, I guess you have to send an UDP packet 
somewhere, but I never did it. If you find it out, please post it.


 
  412   17 Oct 2007 Randolf PohlForumAdding MIDAS .root-files
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
  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 ...
  1012   10 Jul 2014 Clemens SauerzopfForumAdding Interrupt handling to SIS3100 driver
Hello,

we are using the Struck SIS 3100 VME interface for our experiment, but the midas
driver doesn't have interrupt control integrated. Previously we were happy with
just periodic readout, but our requirements have changed so I thought I could
just implement this as there is a demo program provided by Struck on how to use
their driver with interrupts.

Could you recommend an existing midas driver that has a good implementation of
the midas interrupt functions (mvme_interrupt_*) just for me too use as a guideline?

Best regards,
Clemens Sauerzopf
  1013   11 Jul 2014 Pierre-Andre AmaudruzForumAdding Interrupt handling to SIS3100 driver
> Hello,
> 
> we are using the Struck SIS 3100 VME interface for our experiment, but the midas
> driver doesn't have interrupt control integrated. Previously we were happy with
> just periodic readout, but our requirements have changed so I thought I could
> just implement this as there is a demo program provided by Struck on how to use
> their driver with interrupts.
> 
> Could you recommend an existing midas driver that has a good implementation of
> the midas interrupt functions (mvme_interrupt_*) just for me too use as a guideline?
> 
> Best regards,
> Clemens Sauerzopf

Hi Clemens,

We did have interrupt handling at some point under VxWorks and later with Linux, but it 
has always been a challenge.
As you may have found, the current frontend (mfe.c) still has some code to that purpose. 
But I wouldn't guarantee that recent development related to multi-threading didn't 
affect the expected interrupt operation (not been tested).

Now-a-days, I would suggest that you encapsulate your interrupt handling function based 
on the provided software into a independent thread started by a standard midas frontend. 
While the main frontend task could operate a periodic equipment as you've done so far, a 
polling equipment would poll on the data availability from the ring buffer. The readout 
function would compose the appropriate data bank.

This method has the advantage to decouple all the interrupt timing/restriction related 
issues from midas and run a conventional frontend. The ring buffer functions are part of 
midas (rb_...()).
Example for multi-threading can be found in examples/mtfe which include the use of the 
ring buffer as well.

Cheers, PAA
  1015   14 Jul 2014 Clemens SauerzopfForumAdding Interrupt handling to SIS3100 driver
Hi Pierre-Andre,

thanks for your comments. If I understand you correctly you are advising to separate the
triggering based on the interrupt signal and the actual data readout. In principal wouldn't
it be also possible to facilitate the multi-threading equipment type to poll the trigger
signal? Then veto new triggers and start the readout of the different detector modules by a
"manual trigger" ?

I'll check the example you've recommended to compare the different solutions.

By the way I've written a driver for the CAEN V1742 VME module, it's working but the code is
currently not in a "nice" state. but if you are interested I could provide the driver code.

Cheers,
Clemens

> > Hello,
> > 
> > we are using the Struck SIS 3100 VME interface for our experiment, but the midas
> > driver doesn't have interrupt control integrated. Previously we were happy with
> > just periodic readout, but our requirements have changed so I thought I could
> > just implement this as there is a demo program provided by Struck on how to use
> > their driver with interrupts.
> > 
> > Could you recommend an existing midas driver that has a good implementation of
> > the midas interrupt functions (mvme_interrupt_*) just for me too use as a guideline?
> > 
> > Best regards,
> > Clemens Sauerzopf
> 
> Hi Clemens,
> 
> We did have interrupt handling at some point under VxWorks and later with Linux, but it 
> has always been a challenge.
> As you may have found, the current frontend (mfe.c) still has some code to that purpose. 
> But I wouldn't guarantee that recent development related to multi-threading didn't 
> affect the expected interrupt operation (not been tested).
> 
> Now-a-days, I would suggest that you encapsulate your interrupt handling function based 
> on the provided software into a independent thread started by a standard midas frontend. 
> While the main frontend task could operate a periodic equipment as you've done so far, a 
> polling equipment would poll on the data availability from the ring buffer. The readout 
> function would compose the appropriate data bank.
> 
> This method has the advantage to decouple all the interrupt timing/restriction related 
> issues from midas and run a conventional frontend. The ring buffer functions are part of 
> midas (rb_...()).
> Example for multi-threading can be found in examples/mtfe which include the use of the 
> ring buffer as well.
> 
> Cheers, PAA
  1016   15 Jul 2014 Pierre-Andre AmaudruzForumAdding Interrupt handling to SIS3100 driver
Hello Clemens,

The hardware readout is triggered by the interrupt within this thread. The main thread poll on  
the data availability (from the rb) to filter/compose the frontend event.
In a similar multi-threaded implementation presently used in a dark matter experiment we start 
as many thread as necessary to constantly poll on the hardware for "data fragment" collection.
The event composition is done in the main thread through polling on the RBs.

Depending on the trigger rate and readout time, we can afford to analyze the data fragment at 
the thread level and add computed/summary information to the ring buffer on a event-by-event 
basis. This facilitate the overall event filtering happening later on in our event builder. 

"polling the trigger signal?", I don't understand. You can poll on the trigger condition but 
then you don't need interrupt.

The original Midas interrupt implementation was to let the interrupt function set a acknowledge 
flag which is picked up by the standard midas polling function (user code) for triggering the 
readout. This method ensure a minimal time spent in the IRQ and works fine for a single thread.

In regards of the CAEN V1742, we do have a VME driver for it, but it hasn't been added to the 
Midas yet (quite recent), but please don't hesitate to send us a copy.

Cheers, PAA

 

> Hi Pierre-Andre,
> 
> thanks for your comments. If I understand you correctly you are advising to separate the
> triggering based on the interrupt signal and the actual data readout. In principal wouldn't
> it be also possible to facilitate the multi-threading equipment type to poll the trigger
> signal? Then veto new triggers and start the readout of the different detector modules by a
> "manual trigger" ?
> 
> I'll check the example you've recommended to compare the different solutions.
> 
> By the way I've written a driver for the CAEN V1742 VME module, it's working but the code is
> currently not in a "nice" state. but if you are interested I could provide the driver code.
> 
> Cheers,
> Clemens
> 
> > > Hello,
> > > 
> > > we are using the Struck SIS 3100 VME interface for our experiment, but the midas
> > > driver doesn't have interrupt control integrated. Previously we were happy with
> > > just periodic readout, but our requirements have changed so I thought I could
> > > just implement this as there is a demo program provided by Struck on how to use
> > > their driver with interrupts.
> > > 
> > > Could you recommend an existing midas driver that has a good implementation of
> > > the midas interrupt functions (mvme_interrupt_*) just for me too use as a guideline?
> > > 
> > > Best regards,
> > > Clemens Sauerzopf
> > 
> > Hi Clemens,
> > 
> > We did have interrupt handling at some point under VxWorks and later with Linux, but it 
> > has always been a challenge.
> > As you may have found, the current frontend (mfe.c) still has some code to that purpose. 
> > But I wouldn't guarantee that recent development related to multi-threading didn't 
> > affect the expected interrupt operation (not been tested).
> > 
> > Now-a-days, I would suggest that you encapsulate your interrupt handling function based 
> > on the provided software into a independent thread started by a standard midas frontend. 
> > While the main frontend task could operate a periodic equipment as you've done so far, a 
> > polling equipment would poll on the data availability from the ring buffer. The readout 
> > function would compose the appropriate data bank.
> > 
> > This method has the advantage to decouple all the interrupt timing/restriction related 
> > issues from midas and run a conventional frontend. The ring buffer functions are part of 
> > midas (rb_...()).
> > Example for multi-threading can be found in examples/mtfe which include the use of the 
> > ring buffer as well.
> > 
> > Cheers, PAA
  1018   06 Aug 2014 Clemens SauerzopfForumAdding Interrupt handling to SIS3100 driver
Hello Pierre-Andre,

thank you for your help with the interrupt handling. To close this case I'll
attach my interrupt
handling code for the SIS 3100 to this post as a reference. Maybe someone wants
to do something
similar in the future. 

I've decide to go for a C++ frontend therefore it is a class that handles
everything. The user only
has to provide a function pointer to the constructor that handles the interrupt
bitmask. The
interrupt handling is done with a timedwait within a separate thread. 

Cheers,
Clemens

> Hello Clemens,
> 
> The hardware readout is triggered by the interrupt within this thread. The
main thread poll on  
> the data availability (from the rb) to filter/compose the frontend event.
> In a similar multi-threaded implementation presently used in a dark matter
experiment we start 
> as many thread as necessary to constantly poll on the hardware for "data
fragment" collection.
> The event composition is done in the main thread through polling on the RBs.
> 
> Depending on the trigger rate and readout time, we can afford to analyze the
data fragment at 
> the thread level and add computed/summary information to the ring buffer on a
event-by-event 
> basis. This facilitate the overall event filtering happening later on in our
event builder. 
> 
> "polling the trigger signal?", I don't understand. You can poll on the trigger
condition but 
> then you don't need interrupt.
> 
> The original Midas interrupt implementation was to let the interrupt function
set a acknowledge 
> flag which is picked up by the standard midas polling function (user code) for
triggering the 
> readout. This method ensure a minimal time spent in the IRQ and works fine for
a single thread.
> 
> In regards of the CAEN V1742, we do have a VME driver for it, but it hasn't
been added to the 
> Midas yet (quite recent), but please don't hesitate to send us a copy.
> 
> Cheers, PAA
> 
Attachment 1: sis3100.hh
/*! 
  \file sis3100.hh
  \brief provides an interface for interrupt handling with the Struck SIS3100 VME interface
  \author Clemens Sauerzopf <clemens.sauerzopf@oeaw.ac.at>  
  \date 06.08.2014
  \version 1.0
*/ 


#ifndef __SIS3100_HH__
#define __SIS3100_HH__

#include<stdint.h>
#include<sys/types.h>

 #if HAVE_MIDAS__
 extern "C" {
 #include "midas.h"
 #include "sis3100/linux/sis3100_vme_calls.h"
 #include "sis3100/linux/sis1100_var.h"
 }
 #else
 #include <pthread.h>
 #include "sis3100/linux/sis3100_vme_calls.h"
 #include "sis3100/linux/sis1100_var.h"
 #endif

//! interrupt frontend handling class for SIS 3100 VME interface with veto gate and trigger generation
/*!
  This class provides an easy to use interface for handling interrupts with the Stuck SIS3100 VME 
  interface. When using this class create an instance and pass an unused device number to the 
  constructor and a function pointer to handle the interrupt. 

  The interrupt handling is done in a separate thread that waits with a timeout of 500 ms for a 
  SIGUSR1 signal from the SIS kernel driver. In case of a timeout the loop checks if a thread stop 
  signal from midas is present and then waits again for an interrupt. If an interrupt occurs the
  interrupt vector is loaded and a veto gate is produced by the @ref startVeto function on the 
  NIM port 1. Afterwards a user supplied function that takes the interrupt bitask, the highest 
  interrupt level and its vector as arguments is executed. After that the interrupts get acknowledged
  and the veto gate is closed.

  This class uses a separate device to avoid race conditions and for the low level interface to the
  irq setup.
 */
class sis3100 {
public:
  sis3100(int sisDeviceNum,  bool (*eventFunction)(int,int,int));
  bool enableFrontInterrupts();
  bool disbaleFrontInterrupts();
  bool enableVMEInterrupts();
  bool disbaleVMEInterrupts();

  bool enableOutputs();
  bool disableOutputs();

  static inline void startVeto(int p)       {s3100_control_write(p, 0x80, 0x00000001);}
  static inline void stopVeto(int p)        {s3100_control_write(p, 0x80, 0x00010000);}
  static inline void startVeto2(int p)      {s3100_control_write(p, 0x80, 0x00000002);}
  static inline void stopVeto2(int p)       {s3100_control_write(p, 0x80, 0x00020000);}
  static inline void generateTrigger(int p) {s3100_control_write(p, 0x80, 0x02000000);}

  inline bool isOpen() const {return (p==-1 ? false : true);}

  inline void setIsRunning(bool isRun){isRunning = isRun;}
private:
  int p; // SIS3100 device handler

  u_int32_t iobits;
  struct sis1100_irq_ctl irqctl;
  struct sis1100_irq_get irqget;
  struct sis1100_irq_ack irqack; 
  sigset_t mask, old_mask;

  bool isRunning;

  // for testing
#if HAVE_MIDAS__
  midas_thread_t thread;
#else
  pthread_t thread;
#endif

  static 
#if HAVE_MIDAS__
  INT
#else
  void*
#endif
 interruptThread(void *param);

  struct threadInit {
    bool (*eventFunction)(int, int, int);
    bool *isRunning;
    int p; // SIS3100 device handler
    u_int32_t *iobits;
    struct sis1100_irq_ctl *irqctl;
    struct sis1100_irq_get *irqget;
    struct sis1100_irq_ack *irqack; 
    sigset_t mask;
    struct timespec waitTime;
  };

  threadInit threadData;
};

#endif // compile guard
Attachment 2: sis3100.hh
/*! 
  \file sis3100.hh
  \brief provides an interface for interrupt handling with the Struck SIS3100 VME interface
  \author Clemens Sauerzopf <clemens.sauerzopf@oeaw.ac.at>  
  \date 06.08.2014
  \version 1.0
*/ 


#ifndef __SIS3100_HH__
#define __SIS3100_HH__

#include<stdint.h>
#include<sys/types.h>

 #if HAVE_MIDAS__
 extern "C" {
 #include "midas.h"
 #include "sis3100/linux/sis3100_vme_calls.h"
 #include "sis3100/linux/sis1100_var.h"
 }
 #else
 #include <pthread.h>
 #include "sis3100/linux/sis3100_vme_calls.h"
 #include "sis3100/linux/sis1100_var.h"
 #endif

//! interrupt frontend handling class for SIS 3100 VME interface with veto gate and trigger generation
/*!
  This class provides an easy to use interface for handling interrupts with the Stuck SIS3100 VME 
  interface. When using this class create an instance and pass an unused device number to the 
  constructor and a function pointer to handle the interrupt. 

  The interrupt handling is done in a separate thread that waits with a timeout of 500 ms for a 
  SIGUSR1 signal from the SIS kernel driver. In case of a timeout the loop checks if a thread stop 
  signal from midas is present and then waits again for an interrupt. If an interrupt occurs the
  interrupt vector is loaded and a veto gate is produced by the @ref startVeto function on the 
  NIM port 1. Afterwards a user supplied function that takes the interrupt bitask, the highest 
  interrupt level and its vector as arguments is executed. After that the interrupts get acknowledged
  and the veto gate is closed.

  This class uses a separate device to avoid race conditions and for the low level interface to the
  irq setup.
 */
class sis3100 {
public:
  sis3100(int sisDeviceNum,  bool (*eventFunction)(int,int,int));
  bool enableFrontInterrupts();
  bool disbaleFrontInterrupts();
  bool enableVMEInterrupts();
  bool disbaleVMEInterrupts();

  bool enableOutputs();
  bool disableOutputs();

  static inline void startVeto(int p)       {s3100_control_write(p, 0x80, 0x00000001);}
  static inline void stopVeto(int p)        {s3100_control_write(p, 0x80, 0x00010000);}
  static inline void startVeto2(int p)      {s3100_control_write(p, 0x80, 0x00000002);}
  static inline void stopVeto2(int p)       {s3100_control_write(p, 0x80, 0x00020000);}
  static inline void generateTrigger(int p) {s3100_control_write(p, 0x80, 0x02000000);}

  inline bool isOpen() const {return (p==-1 ? false : true);}

  inline void setIsRunning(bool isRun){isRunning = isRun;}
private:
  int p; // SIS3100 device handler

  u_int32_t iobits;
  struct sis1100_irq_ctl irqctl;
  struct sis1100_irq_get irqget;
  struct sis1100_irq_ack irqack; 
  sigset_t mask, old_mask;

  bool isRunning;

  // for testing
#if HAVE_MIDAS__
  midas_thread_t thread;
#else
  pthread_t thread;
#endif

  static 
#if HAVE_MIDAS__
  INT
#else
  void*
#endif
 interruptThread(void *param);

  struct threadInit {
    bool (*eventFunction)(int, int, int);
    bool *isRunning;
    int p; // SIS3100 device handler
    u_int32_t *iobits;
    struct sis1100_irq_ctl *irqctl;
    struct sis1100_irq_get *irqget;
    struct sis1100_irq_ack *irqack; 
    sigset_t mask;
    struct timespec waitTime;
  };

  threadInit threadData;
};

#endif // compile guard
  2289   14 Oct 2021 Amy RobertsSuggestionAdding (or improving discoverability) of TID for odbset
Creating an ODB key requires users to know the Type ID that are defined in 
https://bitbucket.org/tmidas/midas/src/develop/include/midas.h starting at line 320.

I can't find any information on the Midas Wiki about these values or how to find 
them.

Am I missing something obvious?  Is there a way to improve how to find these values?  
Or is this not the best way to interact with the ODB?
  2290   15 Oct 2021 Stefan RittSuggestionAdding (or improving discoverability) of TID for odbset
> Creating an ODB key requires users to know the Type ID that are defined in 
> https://bitbucket.org/tmidas/midas/src/develop/include/midas.h starting at line 320.
> 
> I can't find any information on the Midas Wiki about these values or how to find 
> them.
> 
> Am I missing something obvious?  Is there a way to improve how to find these values?  
> Or is this not the best way to interact with the ODB?

Well, you found them in midas.h, so where is the problem?

If you want a more detailed description, just look in the midas documentation (RTFM):

https://midas.triumf.ca/MidasWiki/index.php/Midas_Data_Types

If you want a more modern interface to the ODB without these data types, look here:

https://midas.triumf.ca/MidasWiki/index.php/Odbxx

Best regards,
Stefan
  720   17 Sep 2010 Konstantin OlchanskiInfoAdded mserver host based access control
In svn rev 4825, I added host based access control to mserver (the MIDAS RPC server). The implementation 
is a verbatim copy mhttpd host based access control list (-a command line switch).

Same as for mhttpd, "mserver -a hostname" enables access control and only permits access from listed 
host names (supply multiple -a switches for multiple hostnames).

This access control does not apply yet for the MIDAS RPC socket connections between MIDAS clients used 
to do RPC callbacks, i.e. to request run transitions. Each MIDAS program is listening for MIDAS RPC 
connections on a high TCP port and at present accepts connections from anybody. To implement access 
controls one could add "-a" switches to every midas application (lot of work) or fill the access control list 
automatically from ODB. mserver still has to use the "-a" command line switches because there is no ODB 
connection when it has to accept or reject remote sockets.

svn rev 4825
K.O.
  224   19 Sep 2005 Konstantin OlchanskiInfoAdded driver for the Wiener CC-USB CAMAC interface
Commited to CVS is the preliminary driver for the Wiener CC-USB CAMAC interface.
The driver implements all the mcstd.h camac access functions, except for those
not supported by hardware (8-bit operations, interrupts) and a few esoteric
functions not implemented in any other camac driver. The driver uses the
musbstd.h library to access USB, also commited in preliminary form.

Affected files:
midas/Makefile (added musbstd.c to libmidas.{a,so})
include/musbstd.h, src/musbstd.c (preliminary USB access library)
drivers/bus/ccusb.{c,h}

Most of the CAMAC access functions have been tested (see comments in ccusb.c).
If you find errors and problems, please email me (olchansk@triumf.ca) or write
an elog reply to this elog message.

Missing is the documentation and finalization of USB access library.
Missing is conformity to some MIDAS coding conventions.

Enjoy,
K.O.
  404   29 Aug 2007 Konstantin OlchanskiInfoAdded data compression to mlogger
I now commited the changes to mlogger (mlogger.c, msystem.h) implementing data
compression using zlib (svn revision 3845)

To enable compression, observe that mlogger is compiled with -DHAVE_ZLIB (see
the Makefile), in "/Logger/Channels/NNN/Settings", set "compression" to "1" and
the filename to "run%05d.mid.gz" (note the suffix ".gz").

In the Makefile, I only enabled HAVE_ZLIB for Linux, as that is the only
platform I tested. If somebody can test compression on Windows, please do and
let us know.

My ROOT analyzer (rootana) package can read compressed MIDAS files directly and
if one wants to add this capability to other MIDAS-related packages, one is
welcome to use my TMidasFile.cxx as an example
(http://ladd00.triumf.ca/viewcvs/rootana/trunk/TMidasFile.cxx?view=markup).

K.O.
  2220   17 Jun 2021 Joseph McKennaInfoAdd support for rtsp camera streams in mlogger (history_image.cxx)
mlogger (history_image) now supports rtsp cameras, in ALPHA we have 
acquisitioned several new network connected cameras. Unfortunately they dont 
have a way of just capturing a single frame using libcurl


========================================
Motivation to link to OpenCV libraries
========================================

After looking at the ffmpeg libraries, it seemed non trivial to use them to 
listen to a rtsp stream and write a series of jpgs.

OpenCV became an obvious choice (it is itself linked to ffmpeg and 
gstreamer), its a popular, multiplatform, open source library that's easy to 
use. It is available in the default package managers in centos 7 and ubuntu 
(an is installed by default on lxplus).

========================================
How it works:
========================================

The framework laid out in history_image.cxx is great. A separate thread is 
dedicated for each camera. This is continued with the rtsp support, using 
the same periodicity:

if (ss_time() >= o["Last fetch"] + o["Period"]) {
An rtsp camera is detected by its URL, if the URL starts with ‘rtsp://’ its 
obvious its using the rtsp protocol and the cv::VideoCapture object is 
created (line 147).

If the connection fails, it will continue to retry, but only send an error 
message on the first 10 attempts (line 150). This counter is reset on 
successful connection
If MIDAS has been built without OpenCV, mlogger will send an error message 
that OpenCV is required if a rtsp URL is given (line 166)
The VideoCapture ‘stays live' and will grab frames from the camera based on 
the sleep, saving to file based on the Period set in the ODB.

If the VideoCapture object is unable to grab a frame, it will release() the 
camera, send an error message to MIDAS, then destroy itself, and create a 
new version (this destroy and create fully resets the connection to a 
camera, required if its on flaky wifi)
If the VideoCapture gets an empty frame, it also follows the same reset 
steps.
If the VideoCaption fills a cv::Frame object successfully, the image is 
saved to disk in the same way as the curl tools.

========================================
Concerns for the future:
========================================

VideoCapture is decoding the video stream in the background, allowing us to 
grab frames at will. This is nice as we can be pretty agnostic to the video 
format in the stream (I tested with h264 from a TP-LINK TAPO C100, but the 
CPU usage is not negligible.

I noticed that this used ~2% of the CPU time on an intel i7-4770 CPU, given 
enough cameras this is considerable. In ALPHA, I have been testing with 10 
cameras:
elog:2220/1 

My suggestion / request would be to move the camera management out of 
mlogger and into a new program (mcamera?), so that users can choose to off 
load the CPU load to another system (I understand the OpenCV will use GPU 
decoders if available also, which can also lighten the CPU load).
Attachment 1: unnamed.png
unnamed.png
  2224   18 Jun 2021 Konstantin OlchanskiInfoAdd support for rtsp camera streams in mlogger (history_image.cxx)
> mlogger (history_image) now supports rtsp cameras

my goodness, we will drive the video surveillance industry out of business.

> My suggestion / request would be to move the camera management out of 
> mlogger and into a new program (mcamera?), so that users can choose to off 
> load the CPU load to another system (I understand the OpenCV will use GPU 
> decoders if available also, which can also lighten the CPU load).

every 2 years I itch to separate mlogger into two parts - data logger
and history logger.

but then I remember that the "I" in MIDAS stands for "integrated",
and "M" stands for "maximum" and I say, "nah..."

(I guess we are not maximum integrated enough to have mhttpd, mserver
and mlogger to be one monolithic executable).

There is also a line of thinking that mlogger should remain single-threaded
for maximum reliability and ease of debugging. So if we keep adding multithreaded
stuff to it, perhaps it should be split-apart after all. (anything that makes
the size of mlogger.cxx smaller is a good thing, imo).

K.O.
ELOG V3.1.4-2e1708b5