ID |
Date |
Author |
Topic |
Subject |
415
|
17 Oct 2007 |
John M O'Donnell | Forum | Adding 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 Sauerzopf | Forum | Adding 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 Amaudruz | Forum | Adding 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 Sauerzopf | Forum | Adding 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 Amaudruz | Forum | Adding 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 Sauerzopf | Forum | Adding 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 Roberts | Suggestion | Adding (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 Ritt | Suggestion | Adding (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 Olchanski | Info | Added 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 Olchanski | Info | Added 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 Olchanski | Info | Added 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 McKenna | Info | Add 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
|
|
2224
|
18 Jun 2021 |
Konstantin Olchanski | Info | Add 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. |
316
|
27 Dec 2006 |
Eric-Olivier LE BIGOT | Forum | Access to out_info from mana.c | Hello,
Is it possible to access out_info (defined in mana.c) from another program?
In fact, out_info is now defined as an (anonymous) "static struct" in mana.c,
which it seems to me precludes any direct use in another program. Is there an
indirect way of getting ahold of out_info? or of the information it contains?
out_info used to be defined as a *non-static* struct, and the code I'm currently
modifying used to compile seamlessly: it now stops the compilation during
linking time, as out_info is now static and the program I have to compile
contains an "extern struct {} out_info".
Any help would be much appreciated! I searched in vain in this forum for
details about out_info and I really need to access the information it contains!
EOL (a pure MIDAS novice) |
317
|
05 Jan 2007 |
Eric-Olivier LE BIGOT | Suggestion | Access to out_info from mana.c | Would it be relevant to transform out_info into a *non-static* variable of a type
defined by a *named* struct?
Currently, programs that try to access out_info cannot do it anymore; and they
typically copy the struct definition from mana.c, which is not robust against future
changes in mana.c.
If mana.c could be changed in the way described above, that would be great .
Otherwise, is it safe to patch it myself for local use? or is there a better way of
accessing out_info from mana.c?
As always, any help would be much appreciated :)
EOL
> Hello,
>
> Is it possible to access out_info (defined in mana.c) from another program?
>
> In fact, out_info is now defined as an (anonymous) "static struct" in mana.c,
> which it seems to me precludes any direct use in another program. Is there an
> indirect way of getting ahold of out_info? or of the information it contains?
>
> out_info used to be defined as a *non-static* struct, and the code I'm currently
> modifying used to compile seamlessly: it now stops the compilation during
> linking time, as out_info is now static and the program I have to compile
> contains an "extern struct {} out_info".
>
> Any help would be much appreciated! I searched in vain in this forum for
> details about out_info and I really need to access the information it contains!
>
> EOL (a pure MIDAS novice) |
318
|
08 Jan 2007 |
Stefan Ritt | Suggestion | Access to out_info from mana.c | I changed out_info into a global structure definition ANA_OUTPUT_INFO and put it into
midas.h, so it can be accessed easily from the user analyzer source code.
> Would it be relevant to transform out_info into a *non-static* variable of a type
> defined by a *named* struct?
> Currently, programs that try to access out_info cannot do it anymore; and they
> typically copy the struct definition from mana.c, which is not robust against future
> changes in mana.c.
>
> If mana.c could be changed in the way described above, that would be great .
> Otherwise, is it safe to patch it myself for local use? or is there a better way of
> accessing out_info from mana.c?
>
> As always, any help would be much appreciated :)
>
> EOL
>
> > Hello,
> >
> > Is it possible to access out_info (defined in mana.c) from another program?
> >
> > In fact, out_info is now defined as an (anonymous) "static struct" in mana.c,
> > which it seems to me precludes any direct use in another program. Is there an
> > indirect way of getting ahold of out_info? or of the information it contains?
> >
> > out_info used to be defined as a *non-static* struct, and the code I'm currently
> > modifying used to compile seamlessly: it now stops the compilation during
> > linking time, as out_info is now static and the program I have to compile
> > contains an "extern struct {} out_info".
> >
> > Any help would be much appreciated! I searched in vain in this forum for
> > details about out_info and I really need to access the information it contains!
> >
> > EOL (a pure MIDAS novice) |
5
|
14 Jan 2004 |
Razvan Stefan Gornea | | Access to hardware in the MIDAS framework | I am just starting to explore MIDAS, i.e. reading the manual and trying
some examples. For the moment I would like to make a simple frontend that
access a portable multimeter through RS-232 port. I think this could help
me understand how to access hardare inside MIDAS framework. Initially I've
started from the MiniFE.c example and tried to initialize the serial port
on run start transition and build a readout loop in the main function. I
know that this is not a full frontend but I was just interested in getting
some experience with the drivers available in the distribution, in this
case RS-232. The portable multimeter is very simple in principle, one just
has to configure the port settings and then send character 'R' and read 14
ASCII characters from the device. Unfortunately I could not understand how
to invoke the driver services so I changed and started again with the
slowcont/frontend.c example. From this example and after reading the "Slow
Control System" section in the MIDAS manual I think that all I need to do
is to define my own equipment structure based on the multi.c class driver
with a single input channel (and replace the null driver with the RS-232).
Here I got stuck. I see from the code source that there is a relationship
between drivers at all levels (even bus) and the ODB but I don't yet fully
understand how they work. Actually for a couple of days now I am in a loop
going from class to device to bus and then back again to class drivers
trying to see how to create my own device driver and especially how to call
the bus driver. It could be that the framework is invoking the drivers and
the user just has to configure things ... up to now I didn't dare to look
at the mfe.c.
Is there a more detailed documentation about slow control and drivers then
the MIDAS manual? What is the data flow through the three layers system for
drivers? What is the role of the framework and what is left to the user
choice?
Thanks |
6
|
14 Jan 2004 |
Stefan Ritt | | Access to hardware in the MIDAS framework | There is some information at
http://midas.triumf.ca/doc/html/Internal.html#Slow_Control_system
and at
http://midas/download/course/course_rt03.zip , file "part1.ppt", expecially
page 59 and page 62 "writing your own device driver".
So what you are missing for your application is a "device driver" for your
multimeter. The only function it has to implement is the function CMD_INIT
where you initialize the RS232 port, and the funciton CMD_GET, which sends
a "R" and reads the value. Now you have two options:
1) You implement RS232 calls directly in your device driver
You link against rs232.c and directly call rs232_init() at the inizialization,
then call rs232_write() and rs232_read() where you read your 14 ASCII
characters.
2) You call a "bus driver" in your device driver
This method makes the device driver independent of the underlying transport
interface. So if your next multimeter accepts the same "R" command over
Ethernet, you can just replace the RS232 bus driver by the TCPIP bus driver
without having to change your device driver. But I guess that method 2) is not
worth for such a simple device like your multimeter.
So take nulldev.c or dastemp.c as your starting point, put some RS232
initialization into the init routine and the communication via "R" into
the "get" routine. The slow control frontend, driven by mfe.c, should then
regularly read your multimeter and the value should appear in the ODB. Take
the examples/slowcont/frontend.c as an example, and adjust the multi_driver[]
list to use your new device driver (instead of the nulldev).
I would like to mention that the usage of midas only makes sense for some
experiemnts which require event based readout, using VME or CAMAC crates. If
your only task is to read out some devices which are called "slow control
equipment" in the midas language, then you might be better of with labview or
something. |
7
|
16 Jan 2004 |
Razvan Stefan Gornea | | Access to hardware in the MIDAS framework | The multimeter device is indeed to simple to use MIDAS but I am just trying
it as a learning experience. The DAQ system to develop involves VME crates
and general purpose I/O boards. The slow control part, especially accessing
the I/O boards seem to me more complex then the VME access. I want to
understand very well the "correct" way of using the MIDAS slow control
framework before starting the project.
I chose the second method and created a meterdev.c driver (essentially a
copy of the nulldev.c) where I changed the init. function and the get
function. I am not sending a "INIT ..." string because for this device it
is useless. In the get function I send a "D" and read my string. I changed
the frontend of the example to have a new driver list (in the first try I
eliminated the Output device but the ODB got corrupted, I guess the class
multi needs to have defined output channels). The output channel is linked
with nulldev and null (I guess this is like if they would not be present).
The result is strange because the get function is called all the time very
fast (much faster then the 9 seconds as set in the equipment) and even
before starting the run (I just put the flag RO_RUNNING).
Thanks for any help |
Attachment 1: frontend.c
|
//********************************************************************************************
//
// Name: frontend.c
// Created by: Razvan Stefan Gornea
//
// Contents: Slow Control frontend for a portable multimeter
//
// Log: 2004-01-15 14:22
// Writing down initial code.
//
//********************************************************************************************
#include <stdio.h>
#include "midas.h"
#include "class/multi.h"
#include "device/nulldev.h"
#include "meterdev.h"
#include "bus/null.h"
#include "bus/rs232.h"
// globals variables
// frontend name
char *frontend_name = "Slow Control";
// frontend file name
char *frontend_file_name = __FILE__;
// frontend loop
BOOL frontend_call_loop = FALSE;
// frontend display refresh
INT display_period = 1000;
// maximum event size in bytes
INT max_event_size = 10000;
// maximum event size for fragments in bytes
INT max_event_size_frag = 5*1024*1024;
// buffer size in bytes
INT event_buffer_size = 10*10000;
// equipment list
// device drivers
DEVICE_DRIVER multi_driver[] = {
{"Input", meterdev, 1, rs232, DF_INPUT},
{"Output", nulldev, 1, null, DF_OUTPUT},
{""}
};
// equipment list
EQUIPMENT equipment[] = {
{ "Multimeter", /* equipment name */
11, 0, /* event ID, trigger mask */
"SYSTEM", /* event buffer */
EQ_SLOW, /* equipment type */
0, /* event source */
"FIXED", /* format */
TRUE, /* enabled */
RO_RUNNING, /* read when running */
9000, /* read every 9 sec */
0, /* stop run after this event limit */
0, /* number of sub events */
1, /* log history every event */
"", "", "",
cd_multi_read, /* readout routine */
cd_multi, /* class driver main routine */
multi_driver, /* device driver list */
NULL, /* init string */
},
{ "" }
};
// routines
INT poll_event(INT source[], INT count, BOOL test) {return 1;};
INT interrupt_configure(INT cmd, INT source[], PTYPE adr) {return 1;};
// frontend initialization
INT frontend_init()
{
return CM_SUCCESS;
}
// frontend exit
INT frontend_exit()
{
return CM_SUCCESS;
}
// frontend loop
INT frontend_loop()
{
return CM_SUCCESS;
}
// begin of run
INT begin_of_run(INT run_number, char *error)
{
return CM_SUCCESS;
}
// end of run
INT end_of_run(INT run_number, char *error)
{
return CM_SUCCESS;
}
// pause run
INT pause_run(INT run_number, char *error)
{
return CM_SUCCESS;
}
// resume run
INT resume_run(INT run_number, char *error)
{
return CM_SUCCESS;
}
|
Attachment 2: meterdev.c
|
//********************************************************************************************
//
// Name: meter.c
// Created by: Razvan Stefan Gornea
//
// Contents: Device driver for a portable multimeter
//
// Log: 2004-01-15 14:22
// Writing down initial code.
//
//********************************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "midas.h"
// globals variables
#define DEFAULT_TIMEOUT 10000 // 10 secondes
typedef struct {
int address;
} METERDEV_SETTINGS;
#define METERDEV_SETTINGS_STR "\
Address = INT : 1\n\
"
typedef struct {
METERDEV_SETTINGS meterdev_settings; // device settings
float *array; // data array
INT num_channels; // number of channels associated with this device
INT (*bd)(INT cmd, ...); // bus driver entry function
void *bd_info; // private settings and data related to the bus driver
HNDLE hkey; // ODB key for bd_info structure
} METERDEV_INFO;
// routines
// initialization function: access the ODB to creates the settings, initializes the variables
// and calls the initialization function of the bus driver
INT meterdev_init(HNDLE hkey, void **pinfo, INT channels, INT (*bd)(INT cmd, ...))
{
int status, size;
HNDLE hDB, hkeydd;
METERDEV_INFO *info;
// allocate info structure
info = calloc(1, sizeof(METERDEV_INFO));
*pinfo = info;
// get handle on current experiment ODB
cm_get_experiment_database(&hDB, NULL);
// create METERDEV settings record
status = db_create_record(hDB, hkey, "DD", METERDEV_SETTINGS_STR); // force the ODB structure to match the METERDEV_SETTINGS C structure
if (status != DB_SUCCESS) {
return FE_ERR_ODB;
}
db_find_key(hDB, hkey, "DD", &hkeydd); // get handle on the DD key in the ODB associated with a certain equipment and device as pointed by the "hkey" handle
size = sizeof(info->meterdev_settings); // get the size of the device settings structure
db_get_record(hDB, hkeydd, &info->meterdev_settings, &size, 0); // load the device settings for the ODB, i.e. ontent of DD key
// initialize the driver
info->num_channels = channels; // define the nmber of channels
info->array = calloc(channels, sizeof(float)); // allocate space for data
info->bd = bd; // set handle on bus driver
info->hkey = hkey; // set handle on the ODB key for the evice driver
if (!bd) { // if handle invalid return error
return FE_ERR_ODB;
}
// call the bus driver initialization routine
status = info->bd(CMD_INIT, info->hkey, &info->bd_info);
if (status != SUCCESS) {
return status;
}
// initialization of device, something like ...
//BD_PUTS("init");
// for this device no initialization string is needed ...
return FE_SUCCESS;
}
// decomission function: free memory allocation(s) and close device(s)
INT meterdev_exit(METERDEV_INFO *info)
{
// call EXIT function of bus driver, usually closes device
info->bd(CMD_EXIT, info->bd_info);
// free local variables
if (info->array) {
free(info->array);
}
free(info);
return FE_SUCCESS;
}
// set channel value
INT meterdev_set(METERDEV_INFO *info, INT channel, float value)
{
char str[80];
// set channel to a specific value, something like ...
sprintf(str, "SET %d %lf", channel, value);
BD_PUTS(str);
BD_GETS(str, sizeof(str), ">", DEFAULT_TIMEOUT);
// simulate writing by storing value in local array, has to be removed in a real driver
if (channel < info->num_channels) {
info->array[channel] = value;
}
return FE_SUCCESS;
}
// set all channels values
INT meterdev_set_all(METERDEV_INFO *info, INT channels, float *value)
{
int i;
char str[1000];
// put here some optimized form of setting all channels simultaneously like ...
strcpy(str, "SETALL ");
for (i=0 ; i<min(info->num_channels, channels) ; i++) {
sprintf(str+strlen(str), "%lf ", value[i]);
}
BD_PUTS(str);
BD_GETS(str, sizeof(str), ">", DEFAULT_TIMEOUT);
// simulate writing by storing values in local array
for (i=0 ; i<min(info->num_channels, channels) ; i++) {
info->array[i] = value[i];
}
return FE_SUCCESS;
}
// get channel value
INT meterdev_get(METERDEV_INFO *info, INT channel, float *pvalue)
{
int status, i;
char str[80];
char ascii_number[5];
// read value from channel, something like ...
//sprintf(str, "GET %d", channel);
sprintf(str, "D"); // request data
BD_PUTS(str);
status = BD_GETS(str, sizeof(str), "\n", DEFAULT_TIMEOUT); // read until getting a cariage return or exit on timeout
for (i = 0; i < 4; i++) { // transfer the number
ascii_number[i] = str[i+4];
}
ascii_number[4] = '\0'; // end of string
*pvalue = (float) atof(ascii_number); // convert from ASCII to float
// simulate reading by copying set data from local array
//if (channel < info->num_channels) {
// *pvalue = info->array[channel];
//}
//else {
// *pvalue = 0.f;
//}
return FE_SUCCESS;
}
// get all channels values
INT meterdev_get_all(METERDEV_INFO *info, INT channels, float *pvalue)
{
// int i;
/* put here some optimized form of reading all channels. If the deviced
does not support such a function, one can call nulldev_get() in a loop
strcpy(str, "GETALL");
BD_PUTS(str);
BD_GETS(str, sizeof(str), ">", DEFAULT_TIMEOUT);
for (i=0 ; i<min(info->num_channels, channels) ; i++)
pvalue[i] = atof(str+i*5); // extract individual values from reply
*/
/* simulate reading by copying set data from local array */
//for (i=0 ; i<min(info->num_channels, channels) ; i++)
// pvalue[i] = info->array[i];
return FE_SUCCESS;
}
// device driver entry point
INT meterdev(INT cmd, ...)
{
va_list argptr;
HNDLE hKey;
INT channel, status;
DWORD flags;
float value, *pvalue;
void *info, *bd;
va_start(argptr, cmd);
status = FE_SUCCESS;
switch (cmd) {
case CMD_INIT:
hKey = va_arg(argptr, HNDLE);
info = va_arg(argptr, void *);
channel = va_arg(argptr, INT);
flags = va_arg(argptr, DWORD);
bd = va_arg(argptr, void *);
status = meterdev_init(hKey, info, channel, bd);
break;
case CMD_EXIT:
info = va_arg(argptr, void *);
status = meterdev_exit(info);
break;
case CMD_SET:
info = va_arg(argptr, void *);
channel = va_arg(argptr, INT);
value = (float) va_arg(argptr, double); // floats are passed as double
status = meterdev_set(info, channel, value);
break;
case CMD_SET_ALL:
info = va_arg(argptr, void *);
channel = va_arg(argptr, INT);
pvalue = (float *) va_arg(argptr, float *);
status = meterdev_set_all(info, channel, pvalue);
break;
case CMD_GET:
info = va_arg(argptr, void *);
channel = va_arg(argptr, INT);
pvalue = va_arg(argptr, float*);
status = meterdev_get(info, channel, pvalue);
break;
case CMD_GET_ALL:
info = va_arg(argptr, void *);
channel = va_arg(argptr, INT);
pvalue = va_arg(argptr, float*);
status = meterdev_get_all(info, channel, pvalue);
break;
default:
break;
}
va_end(argptr);
return status;
}
|
8
|
17 Jan 2004 |
Stefan Ritt | | Access to hardware in the MIDAS framework | > The result is strange because the get function is called all the time very
> fast (much faster then the 9 seconds as set in the equipment) and even
> before starting the run (I just put the flag RO_RUNNING).
This is on purpose. When the frontend is idle, it loops over the slow control
equipment as fast as possible. This way, you see changes in your hardware very
quickly. I see no reason to waste CPU cycles in the frontend when there are
better things to do like reading slow control equipment. Presume you have the
alarm system running, which turns off some equipment in case of an over
current. You better do this as quickly as possible, not wasting up to 9
seconds each time.
The 9 seconds you mention are for reading *EVENTS*. You have double
functionality: First, reading the slow control system, writing updated values
to the ODB, where someone else can display or evaluate them (in the alarm
system for example). Second, assemble events and sending them with the other
data to disk or tape. Only the second one gets controlled by RO_RUNNING and
the 9 seconds. You can see this by the updating event statists on your
frontend display, which increments only when running and then every 9 seconds. |
|