ID |
Date |
Author |
Topic |
Subject |
11
|
11 Mar 2004 |
Renee Poutissou | | Creation of secondary Midas output file. | Jan ,
Do you need to log this stage 1 output? If not, you would use the
eventbuilder mechanism to create your stage 2 events.
I use the eventbuilder mechanism with success for my TWIST experiment.
Renee |
10
|
10 Mar 2004 |
Stefan Ritt | | Creation of secondary Midas output file. | Dear Jan,
I had a look at your code. You create a gPhysicsEventHeader array, fill it, and expect the
framework to write it to disk. But how can the framework "guess" that you want your private
global array being written? Unfortunately it cannot do magic!
Do do what you want, you have to write a "secondary" midas file yourself. I modified your
code to do that. First, I define the event storage like
BYTE gSecEvent[ MAX_EVENT_SIZE ];
EVENT_HEADER *gPhysicsEventHeader = (EVENT_HEADER *) gSecEvent;
WORD* gPhysicsEventData = ( WORD * )( gPhysicsEventHeader + 1 );
I use gSecEvent as a BYTE array, since it only contains one avent at a time, so this is more
appropriate. Then, in the BOR routine, I open a file:
sprintf(str, "sec%05d.mid", run_number);
sec_fh = open(str, O_CREAT | O_RDWR | O_BINARY, 0644);
and close it in the EOR routine
close(sec_fh);
The event routine now manually fills events into the secondary file:
/* write event to secondary .mid file */
gPhysicsEventHeader->data_size = bk_size(gPhysicsEventData);
write(sec_fh, gPhysicsEventHeader, sizeof(EVENT_HEADER)+bk_size(gPhysicsEventData));
Note that this code is placed *inside* the for() loop over nItems, so for each detector you
create and event and write it.
That's all you need, the full file adccalib.c is attached. I tried to produce a sec01220.mid
file and was able to read it back with the mdump utility.
Best regards,
Stefan |
Attachment 1: adccalib.c
|
/********************************************************************\
Name: adccalib.c
Created by: Stefan Ritt
Contents: Example analyzer module for ADC calibration. Looks
for ADC0 bank, subtracts pedestals and applies gain
calibration. The resulting values are appended to
the event as an CADC bank ("calibrated ADC"). The
pedestal values and software gains are stored in
adccalib_param structure which was defined in the ODB
and transferred to experim.h.
\********************************************************************/
/*-- Include files -------------------------------------------------*/
/* standard includes */
#include <stdio.h>
#include <time.h>
#include <io.h>
#include <fcntl.h>
/* midas includes */
#include "midas.h"
#include "experim.h"
#include "analyzer.h"
/* root includes */
#include <TH1F.h>
#include <TTree.h>
#include <TDirectory.h>
/* Local stuff, struct for handling analysis demo...
using EV01_BANK as template for bank mapping */
#define N_STRUCT_ELEMENT 6
#define N_FRONTENDS 14
/* Histo info, could be placed in ODB */
typedef struct {
char name[ 256 ];
char title[ 256 ];
INT nbins;
float xlow;
float xhigh;
} EV_HI_DEF;
EV_HI_DEF h[ N_STRUCT_ELEMENT ]={
{"AreaHG", "AreaHG" , 1024, 0.0, 1023.},
{"AreaLG", "AreaLG" , 1024, 0.0, 1023.},
{"TimeHi", "Time High", 1024, 0.0, 1023.},
{"TimeLo", "Time Low" , 1024, 0.0, 1023.},
{"Detid" , "Detector ID" , 1024, 0.0, 1023.},
{"Slope" , "Slope" , 1024, 0.0, 1023.}
};
/*-- Parameters ----------------------------------------------------*/
/* local creation of ODB struct */
GAMMA_PARAM_STR( gamma_param_str );
GAMMA_PARAM gamma_param;
/* Global ODB struct (taken care by analyzer.c) */
extern EXP_PARAM exp_param;
extern RUNINFO runinfo;
/*-- Module declaration --------------------------------------------*/
INT adc_calib( EVENT_HEADER*, void* );
INT adc_calib_init( void );
INT adc_calib_bor( INT run_number );
INT adc_calib_eor( INT run_number );
/*-- New Bank Area -------------------------------------------------*/
BYTE gSecEvent[ MAX_EVENT_SIZE ];
EVENT_HEADER *gPhysicsEventHeader = (EVENT_HEADER *) gSecEvent;
// Trick used for allocating MAX_EVENT_SIZE bytes for bank.
WORD* gPhysicsEventData = ( WORD * )( gPhysicsEventHeader + 1 );
// Pointer to start of first data record
/* file for secondary .mid file */
int sec_fh;
/* The module name "Gamma" is used for the ODB tree under
/Analyzer/Parameters. It maps the experim.h gamma struct.
*/
ANA_MODULE adc_calib_module = {
"Gamma", /* module name */
"Pierre", /* author */
adc_calib, /* event routine */
adc_calib_bor, /* BOR routine */
adc_calib_eor, /* EOR routine */
adc_calib_init, /* init routine */
NULL, /* exit routine */
&gamma_param, /* parameter structure */
sizeof(gamma_param), /* structure size */
gamma_param_str, /* initial parameters */
};
/*-- module-local variables ----------------------------------------*/
extern TDirectory *gManaHistsDir;
/* Root Histo objects */
static TH1F* gAdcHists[ N_FRONTENDS ];
/*-- init routine --------------------------------------------------*/
#define TM_N_BINS 2048
#define TM_X_LOW 0
#define TM_X_HIGH 40000
INT adc_calib_init(void)
{
char name[ 256 ];
int fe_number = 2;
int i;
char title[256];
// Some booking for demo
// Just book the crystals from frontend 2.
for (i=0; i < N_STRUCT_ELEMENT; i++)
{
sprintf(name, "%s-%2.2i" , h[i].name, fe_number);
sprintf(title, "%s-%2.2i", h[i].title, fe_number);
gAdcHists[i] = (TH1F*)gManaHistsDir->GetList()->FindObject(name);
printf("Booking Histo:%s\n", name);
if (gAdcHists[i] == NULL)
gAdcHists[i] = new TH1F(name, title, h[i].nbins, h[i].xlow, h[i].xhigh);
}
return SUCCESS;
}
/*-- BOR routine ---------------------------------------------------*/
INT adc_calib_bor(INT run_number)
{
char str[80];
sprintf(str, "sec%05d.mid", run_number);
sec_fh = open(str, O_CREAT | O_RDWR | O_BINARY, 0644);
if (sec_fh < 0)
cm_msg(MERROR, "adc_calib_bor", "Cannot open secondary .mid file \"%s\"", str);
return SUCCESS;
}
/*-- eor routine ---------------------------------------------------*/
INT adc_calib_eor(INT run_number)
{
close(sec_fh);
return SUCCESS;
}
/*-- event routine -------------------------------------------------*/
INT adc_calib(EVENT_HEADER *pheader, void *pevent)
{
INT n_items;
DWORD *pdata;
EV01_BANK *pev;
TREK_BANK *trek;
// Initialize the calculate output bank including the header.
gPhysicsEventHeader->serial_number = (DWORD) - 1;
gPhysicsEventHeader->event_id = 2;
gPhysicsEventHeader->trigger_mask = 0;
gPhysicsEventHeader->time_stamp = pheader->time_stamp;
// For demo assume each crystal in bank 2 is new event. This really isn't
// true, but it is analogous to splitting one midas event into multiple physics
// events.
/* Get there with ID = 1 -> EVxx,
For demo histo EV02 EV_BANK all elements.
Create a new bank TREK which is a structure bank.
We are testing the breaking of a single midas event
into individual physics events. Thus we will take
each crystal in EV02 and make it a separate event
in the TREK output bank.
[local:Default:S]Bank switches>set TREK 1
for output
Apply some calibration from the gamma ODB struct.
*/
/* look for EV02 bank, return if not present, skip TMxx ....
n_items: number of elements in the bank */
if ( !( n_items = bk_locate( pevent, "EV02", &pdata ) ) )
return 1;
// Loop through all items in bank.
short nItems = n_items/ sizeof( EV01_BANK );
printf( "Number of bytes %d, number of items %d\n", n_items, nItems );
pev = (EV01_BANK *)pdata;
for ( short i = 0; i < nItems; i++ )
{
/* fill histos not really elegant for now*/
gAdcHists[0]->Fill((float) pev->areahg, 1);
gAdcHists[1]->Fill((float) pev->arealg, 1);
gAdcHists[2]->Fill((float) pev->timehi, 1);
gAdcHists[3]->Fill((float) pev->timelo, 1);
gAdcHists[4]->Fill((float) pev->detid, 1);
gAdcHists[5]->Fill((float) pev->slop, 1);
// create calibrated TREK bank. Recall that this output bank mimics
// the splitting up of the midas bank into physics events.
++(gPhysicsEventHeader->serial_number); // Update serial number.
bk_init32( gPhysicsEventData ); // Initialize storage.
bk_create( gPhysicsEventData, "TREK", TID_STRUCT, &trek );
trek->one = (double) pev->areahg * 1.0;
trek->two = (float) pev->timelo * 1.0;
printf("area: %e time: %f\n", trek->one, trek->two );
bk_close( gPhysicsEventData, trek+1 );
pev++; // Loop to next crystal's data.
/* write event to secondary .mid file */
gPhysicsEventHeader->data_size = bk_size(gPhysicsEventData);
write(sec_fh, gPhysicsEventHeader, sizeof(EVENT_HEADER)+bk_size(gPhysicsEventData));
}
/* close calculated bank */
return SUCCESS;
}
|
9
|
10 Mar 2004 |
Jan Wouters | | Creation of secondary Midas output file. | Dear Midas Team,
I have run into a problem with Midas and was wondering if you could explain what I
am doing wrong. I have included a simple demo to illustrate what I am doing and
can send a small input data file if needed.
WHAT I AM TRYING TO DO:
Every midas event for the DANCE experiment consists of many physics events. I am
trying to create a secondary mid file where the event boundaries are now the
physics events rather than the midas events. This secondary mid file will be
analyzed using a second stage midas analyzer.
For the demo, I use the data from EV02 (one of our 15 frontends), which consists of a
variable number of fixed length structures where each structure contains the data for
one crystal from the DANCE detector.
I treat each crystal as a separate physics event and write it out in the TREK bank,
which is a demo calculated output bank, as a separate event.
(The only difference between this demo and our real system is that we would include
all the crystals from the other frontends that have approximately the same time stamp
in the output bank. Thus the output bank would consist of a varing number of
crystals in one event rather than the fixed one crystal per event used in this demo.)
THE CHANGES TO analyzer.c AND adccalib.c
I loop through the EV02 bank examining each crystal structure in turn. I calculate
"calibrated" parameters and put them into an output bank called TREK. The unusual
part of this example is that the TREK bank is no longer part of the main list of input
banks, ana_trigger_bank_list[]. Instead it is now part of a new bank list called
ana_physics_bank_list[]. See the analyzer.c file for this definition.
In adccalib.c I create the space for this new bank as follows.
EVENT_HEADER gPhysicsEventHeaders[ MAX_EVENT_SIZE / sizeof(
EVENT_HEADER ) ];
WORD* gPhysicsEventData = ( WORD * )( gPhysicsEventHeaders + 1 );
In the adc_calib routine I create the bank header as follows. Note that the serial
numbers will restart at 0 at the beginning of each midas event. Should I let the serial
number increment monotonically until the end of the run?:
gPhysicsEventHeaders->serial_number = (DWORD) - 1;
gPhysicsEventHeaders->event_id = 2;
gPhysicsEventHeaders->trigger_mask = 0;
gPhysicsEventHeaders->time_stamp = pheader->time_stamp;
In a loop that loops through all the crystals contained in EV02, I extract each crystal,
calibrate it, and store it in a TREK structure. In creating the TREK bank I assume that
each one will be a separate physics event thus I update the event serial number and
use bk_init32 to initialize the memory.
for ( short i = 0; i < nItems; i++ )
{ ++(gPhysicsEventHeaders->serial_number); // Update serial number.
bk_init32( gPhysicsEventData ); // Initialize storage.
bk_create( gPhysicsEventData, "TREK", TID_STRUCT, &trek );
trek->one = (double) pev->areahg * 1.0;
trek->two = (float) pev->timelo * 1.0;
bk_close( gPhysicsEventData, trek+1 );
pev++; // Loop to next crystal's data.
}
The output bank should consist of multiple events for each individual EV02 midas
input event.
As far as I can tell the code compiles and runs fine, but I get no data in the .mid
output file except for the ODB. I have a print statement at the beginning of each
midas event stating how many crystals were found in the EV02 bank. I also print out
the calibrated value for each crystal as it is being placed in its own TREK output
bank. The data appears correct.
I cannot place TREK in the input bank the way it normally is done in the examples
because there is not a one-to-one correspondence between a midas event and a
true physics event. Instead one midas event has many physics events. Thus the
output bank needs to be in a new memory area so that I can create a custom header
and increment the serial number properly for each event. Our follow-on analysis
using a second Midas analyzer only needs to analyze one physics event at a time
rather than one Midas event at a time, which is why we are going to all the trouble to
get this paradigm working.
I include all the code for this very simple example.
RUNNING THE CODE:
To run the example just use the run01220.mid file I will send:
./analyzer -i run01220.mid.gz -o run01220out.mid -c settings.odb_cfg -n 50
The only thing done by the settings.odb_cfg file is to turn on the TREK output bank. I
have verified that the bank is on.
SUMMARY:
I believe that I must not be creating the new TREK output bank correctly so that
midas understands that the event-by-event calculated physics data should be written
out event-by-event. I have pointed out several places in the above discussion where
I might be making a mistake.
I would like to get both this example running and a similar which create Root trees,
though the Root trees are of secondary importance. With this example I can finish
writing the second stage analyzer and get the DANCE collaboration moving forward
with their analysis. Currently, we cannot use this paradigm because I cannot create
a secondary mid file in our stage one analysis. I would be very grateful if you could
take a look at this example and tell me what I am doing incorrectly.
Jan |
Attachment 1: dance193.tar
|
66
|
19 Jan 2004 |
Konstantin Olchanski | | darwin aka macosx changes | I commited the final bits to make Midas build on Darwin aka macosx.
Here is the summary:
1) I treat Darwin as a funny linux, so OS_LINUX is always defined
2) OS_DARWIN is defined for places where the two differ
3) system dependant directory is "midas/darwin/{bin,lib}"
4) a few header files had to be moved around to dodge namespace pollution by Apple system
header files (i.e. one of the PowerPC header files #defines PVM- collision with PVM in mana.c,
another #defines Free(x)- collision with ROOT header files)
5) ss_thread_create() and ss_thread_kill() now use midas_thread_t. On Darwin ptherad_t is not
an "int".
6) the Makefile has no support for building the midas shared library on macosx.
7) on my Mac OS 10.2.8 machine, "make all" works, "odbedit" and "mhttpd" run. This is the
full extent of my testing. Status on Mac OS 10.3.x is unknown.
K.O. |
73
|
19 Jan 2004 |
Konstantin Olchanski | | First try- midas on darwin/macosx | > > Simplest solution is to take sys/mount.h out of midasinc.h and include it in system.c
> Agree.
Done.
With this, I commited the rest of my changes: midas_thread_t in midas.h, change ss_thread_xxx() prototypes in msystem.h
, implementation in system.c
My cvs diff is now empty.
Midas should compile on Darwin aka macosx, I tested "odbedit" and "mhttpd"- they seem to work.
> > This uncovered a problem with ss_getthandle().
> The Unix version of ss_getthandle() returns the pid since at the time when I wrote that function (many years ago) there were no threads under Unix. It should now
> be replaces with a function which returns the real thread id (at least under Linux).
I do not want to touch this. Sorry.
K.O. |
72
|
19 Jan 2004 |
Stefan Ritt | | First try- midas on darwin/macosx | > I want this:
>
> mana.c does *not* include sys/mount.h
> system.c does include sys/mount.h
>
> Simplest solution is to take sys/mount.h out of midasinc.h and include it in system.c
Agree.
> This uncovered a problem with ss_getthandle(). What is it supposed to do? On Windows it returns a handle to the current thread, on OS_UNIX, it returns getpid().
> What gives? I am leaving it alone for now.
The Unix version of ss_getthandle() returns the pid since at the time when I wrote that function (many years ago) there were no threads under Unix. It should now
be replaces with a function which returns the real thread id (at least under Linux). |
71
|
18 Jan 2004 |
Konstantin Olchanski | | First try- midas on darwin/macosx | > I would like to keep all OS specific #includes in midasinc.h
No go. Here is the problem:
midasinc.h includes sys/mount.h, which #defines Free(x) to be something else
mana.c includes msystem.h, which includes midasinc.h
mana.c includes ROOT header files, which blow up because Free(x) is redefined.
I want this:
mana.c does *not* include sys/mount.h
system.c does include sys/mount.h
Simplest solution is to take sys/mount.h out of midasinc.h and include it in system.c
> Right, PVM should be replaced by HAVE_PVM.
Commited.
> > Then, a new problem- on MacOSX, pthread_t is not an "INT" and system.c:ss_thread_create() whines about it. I want to
> > introduce a system dependant THREAD_T (or whatever) and make ss_thread_create() return that, rather than INT.
> Good. If you have a OS_MACOSX, that should help you there.
Okey. In Darwin, pthread_t is not an int. It is a pointer to a struct. In midas.c I typedef midas_pthread_t to HANDLE on Windows and to pthread_t n OS_UNIX.
This uncovered a problem with ss_getthandle(). What is it supposed to do? On Windows it returns a handle to the current thread, on OS_UNIX, it returns getpid().
What gives? I am leaving it alone for now.
Attached is the current diff. Most changes are in system.c: ss_timezone() and midas_pthread_t. The Makefile part is already commited. Building the shared
library was made dependant on NEED_SHLIB. Now, building static midas applications is very simple, use "make SHLIB="
K.O. |
Attachment 1: xxx
|
? .ALARM.SHM
? .ELOG.SHM
? .ODB.SHM
? .SYSMSG.SHM
? darwin
? midas.log
? xx
? xxx
Index: Makefile
===================================================================
RCS file: /usr/local/cvsroot/midas/Makefile,v
retrieving revision 1.50
diff -r1.50 Makefile
0a1
>
218a220,224
> #
> # Uncomment the next line to build the midas shared library
> #
> NEED_SHLIB=1
>
268a275,290
> # MacOSX/Darwin is just a funny Linux
> #
> ifeq ($(OSTYPE),Darwin)
> OSTYPE = darwin
> endif
>
> ifeq ($(OSTYPE),darwin)
> OS_DIR = darwin
> OSFLAGS = -DOS_LINUX -DOS_DARWIN -DHAVE_STRLCPY -fPIC -Wno-unused-function
> LIBS = -lpthread
> SPECIFIC_OS_PRG = $(BIN_DIR)/mlxspeaker
> NEED_RANLIB=1
> NEED_SHLIB=
> endif
>
> #-----------------------
340a363,364
> LIB =$(LIBNAME)
> ifdef NEED_SHLIB
342,344c366,367
< LIB = -lmidas
< # Uncomment this for static linking of midas executables
< #LIB = $(LIBNAME)
---
> LIB = $(SHLIB)
> endif
351c374
< $(LIB_DIR)/fal.o $(PROGS)
---
> $(LIB_DIR)/fal.o $(PROGS)
431a455,457
> ifdef NEED_RANLIB
> ranlib $@
> endif
432a459
> ifdef NEED_SHLIB
435a463
> endif
Index: include/midas.h
===================================================================
RCS file: /usr/local/cvsroot/midas/include/midas.h,v
retrieving revision 1.126
diff -r1.126 midas.h
464c464
< #if defined(OS_LINUX) || defined(OS_OSF1) || defined(OS_ULTRIX) || defined(OS_FREEBSD) || defined(OS_SOLARIS) || defined(OS_IRIX)
---
> #if defined(OS_LINUX) || defined(OS_OSF1) || defined(OS_ULTRIX) || defined(OS_FREEBSD) || defined(OS_SOLARIS) || defined(OS_IRIX) || defined(OS_DARWIN)
534a535,544
> #endif
>
> /* need system-dependant thread type */
> #if defined(OS_WINNT)
> typedef HANDLE midas_thread_t;
> #elif defined(OS_UNIX)
> #include <pthread.h>
> typedef pthread_t midas_thread_t;
> #else
> typedef INT midas_thread_t;
Index: include/midasinc.h
===================================================================
RCS file: /usr/local/cvsroot/midas/include/midasinc.h,v
retrieving revision 1.11
diff -r1.11 midasinc.h
50a51
> #include <assert.h>
157d157
< #include <sys/mount.h>
163a164,165
> #ifdef OS_DARWIN
> #else
164a167
> #endif
166a170,172
> #ifdef OS_DARWIN
> #include <util.h>
> #else
167a174
> #endif
Index: include/msystem.h
===================================================================
RCS file: /usr/local/cvsroot/midas/include/msystem.h,v
retrieving revision 1.37
diff -r1.37 msystem.h
719,720c719,720
< INT EXPRT ss_thread_create(INT(*func) (void *), void *param);
< INT EXPRT ss_thread_kill(INT thread_id);
---
> midas_thread_t EXPRT ss_thread_create(INT(*func) (void *), void *param);
> INT EXPRT ss_thread_kill(midas_thread_t thread_id);
721a722
> INT ss_timezone(void);
Index: src/mhttpd.c
===================================================================
RCS file: /usr/local/cvsroot/midas/src/mhttpd.c,v
retrieving revision 1.262
diff -r1.262 mhttpd.c
6983c6983
< x_act = (int) floor((double) (xmin - timezone) / label_dx) * label_dx + timezone;
---
> x_act = (int) floor((double) (xmin - ss_timezone()) / label_dx) * label_dx + ss_timezone();
6995,6996c6995,6996
< if ((x_act - timezone) % major_dx == 0) {
< if ((x_act - timezone) % label_dx == 0) {
---
> if ((x_act - ss_timezone()) % major_dx == 0) {
> if ((x_act - ss_timezone()) % label_dx == 0) {
Index: src/system.c
===================================================================
RCS file: /usr/local/cvsroot/midas/src/system.c,v
retrieving revision 1.78
diff -r1.78 system.c
306a307,310
> #ifdef OS_UNIX
> #include <sys/mount.h>
> #endif
>
895c899
< INT thread handle
---
> INT thread handle
914c918
< return (int) hThread;
---
> return hThread;
1653c1657
< thread_id = ss_thread_spawn((void *) taskWatch, &tsWatch);
---
> midas_thread_t thread_id = ss_thread_create((void *) taskWatch, &tsWatch);
1662c1666
< thread_id = ss_thread_spawn((void *) taskWatch, pDevice);
---
> midas_thread_t thread_id = ss_thread_create((void *) taskWatch, pDevice);
1673c1677
< INT ss_thread_create(INT(*thread_func) (void *), void *param)
---
> midas_thread_t ss_thread_create(INT(*thread_func) (void *), void *param)
1675c1679
< #ifdef OS_WINNT
---
> #if defined(OS_WINNT)
1689,1690c1693
< #endif /* OS_WINNT */
< #ifdef OS_MSDOS
---
> #elif defined(OS_MSDOS)
1694,1695c1697
< #endif /* OS_MSDOS */
< #ifdef OS_VMS
---
> #elif defined(OS_VMS)
1699c1701
< #endif /* OS_VMS */
---
> #elif defined(OS_VXWORKS)
1701d1702
< #ifdef OS_VXWORKS
1719d1719
< #endif /* OS_VXWORKS */
1721c1721,1722
< #ifdef OS_UNIX
---
> #elif defined(OS_UNIX)
>
1728c1729,1730
< #endif /* OS_UNIX */
---
>
> #endif
1738c1740
< thread_id = ss_thread_create((void *) taskWatch, pDevice);
---
> midas_thread_t thread_id = ss_thread_create((void *) taskWatch, pDevice);
1749c1751
< INT ss_thread_kill(INT thread_id)
---
> INT ss_thread_kill(midas_thread_t thread_id)
1751c1753
< #ifdef OS_WINNT
---
> #if defined(OS_WINNT)
1755c1757
< status = TerminateThread((HANDLE) thread_id, 0);
---
> status = TerminateThread(thread_id, 0);
1759,1760c1761
< #endif /* OS_WINNT */
< #ifdef OS_MSDOS
---
> #elif defined(OS_MSDOS)
1764,1765c1765
< #endif /* OS_MSDOS */
< #ifdef OS_VMS
---
> #elif defined(OS_VMS)
1769c1769
< #endif /* OS_VMS */
---
> #elif defined(OS_VXWORKS)
1771d1770
< #ifdef OS_VXWORKS
1773d1771
<
1775d1772
<
1777d1773
< #endif /* OS_VXWORKS */
1779,1782c1775
< #ifdef OS_UNIX
< INT status;
<
< status = pthread_kill((pthread_t) thread_id, SIGKILL);
---
> #elif defined(OS_UNIX)
1783a1777,1778
> INT status;
> status = pthread_kill(thread_id, SIGKILL);
1785c1780,1781
< #endif /* OS_UNIX */
---
>
> #endif
2339c2335
< #ifdef OS_WINNT
---
> #if defined(OS_WINNT)
2356,2357c2352,2358
< #endif
< #ifdef OS_UNIX
---
> #elif defined(OS_DARWIN)
>
> assert(!"ss_settime() is not supported");
> /* not reached */
> return SS_NO_DRIVER;
>
> #elif defined(OS_UNIX)
2361,2362c2362
< #endif
< #ifdef OS_VXWORKS
---
> #elif defined(OS_VXWORKS)
2411a2412,2438
> INT ss_timezone()
> /********************************************************************\
>
> Routine: ss_timezone
>
> Purpose: Returns what?!?
>
> Input:
> none
>
> Output:
> what the heck does it return?!?
>
> Function value:
> INT what is it?!?
>
> \********************************************************************/
> {
> #ifdef OS_DARWIN
> return 0;
> #else
> return timezone; /* on Linux, comes from "#include <time.h>". What is it ?!? */
> #endif
> }
>
>
> /*------------------------------------------------------------------*/
4850c4877
< INT status;
---
> #if defined(OS_DARWIN)
4852c4879,4883
< #ifdef OS_UNIX
---
> return 0;
>
... 14 more lines ...
|
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. |
70
|
17 Jan 2004 |
Stefan Ritt | | First try- midas on darwin/macosx | > With the ALIGN8() change ODB works, mhttpd works. ALIGN8 change now commited to cvs, verified that "make all" builds
> on Linux.
Verified that "make all" still works under Windows.
> ROOT stuff still blows up because of more namespace pollution (/usr/include/sys/something does #define Free(x)
> free(blah...)). Arguably, it is not Apple's fault- portable programs should not include any <sys/foo.h> header files. I
> think I can fix it by moving "#include <sys/mount.h>" from midasinc.h to system.h.
I would like to keep all OS specific #includes in midasinc.h. In worst case put another section there for OSX, like
in midas.h:
#if !defined(OS_MACOSX)
#if defined ( __????__ ) <- put the proper thing here
#define OS_MACOSX
#endif
#endif
then make a new seciton in midasinc.h
#ifdef OS_MACOSX
#include <...>
#endif
> Also figured out why PVM is defined- more pollution from "#include <sys/blah...>". This is only in mana.c and I will
> repace every "#ifdef PVM" with "#ifdef HAVE_PVM". Is there documentation that should be updated as well? Alternatively I
> can try to play games with header files...
Right, PVM should be replaced by HAVE_PVM. This is only for the analyzer. I planned at some point to run the analyzer in
parallel on a linux cluster, but it was never really used. Going to ROOT, that facility should be replaces by PROOF.
> Then, a new problem- on MacOSX, pthread_t is not an "INT" and system.c:ss_thread_create() whines about it. I want to
> introduce a system dependant THREAD_T (or whatever) and make ss_thread_create() return that, rather than INT.
Good. If you have a OS_MACOSX, that should help you there.
-SR |
69
|
16 Jan 2004 |
Konstantin Olchanski | | First try- midas on darwin/macosx | > Great, I got already questions about MacOSX support...
> Once it's working, you should commit the changes.
With the ALIGN8() change ODB works, mhttpd works. ALIGN8 change now commited to cvs, verified that "make all" builds
on Linux.
ROOT stuff still blows up because of more namespace pollution (/usr/include/sys/something does #define Free(x)
free(blah...)). Arguably, it is not Apple's fault- portable programs should not include any <sys/foo.h> header files. I
think I can fix it by moving "#include <sys/mount.h>" from midasinc.h to system.h.
Also figured out why PVM is defined- more pollution from "#include <sys/blah...>". This is only in mana.c and I will
repace every "#ifdef PVM" with "#ifdef HAVE_PVM". Is there documentation that should be updated as well? Alternatively I
can try to play games with header files...
> But take into account that using "//" for comments might cause problems for the VxWorks compiler (talk to Pierre
about that!).
Yes, "// comments" stay out of midas. I used them to make the modification more visible.
> You can rename ALIGN to ALIGN8 all over the place.
Done, commited.
> > - "timezone" in mhttpd.c. On linux, it's an "int", on darwin, it's a function. What gives?
> Wrap it into a function get_timezone(). Under linux, just return "timezone", under OSX,
> return timezone() via conditional compiling.
Right. Still on the todo list.
> > - building libmidas.a requires running ranlib
I still have to cleanup the Makefile. Not commiting it yet.
Then, a new problem- on MacOSX, pthread_t is not an "INT" and system.c:ss_thread_create() whines about it. I want to
introduce a system dependant THREAD_T (or whatever) and make ss_thread_create() return that, rather than INT.
ROOT stuff is still not fully tested- it takes a little while to build ROOT on a 600MHz laptop.
Attached is my current CVS diff.
K.O. |
Attachment 1: xxx
|
? .ALARM.SHM
? .ELOG.SHM
? .ODB.SHM
? .SYSMSG.SHM
? darwin
? midas.log
? xx
? xxx
Index: Makefile
===================================================================
RCS file: /usr/local/cvsroot/midas/Makefile,v
retrieving revision 1.50
diff -r1.50 Makefile
0a1
>
218a220,224
> #
> # Uncomment the next line to build the midas shared library
> #
> NEED_SHLIB=1
>
268a275,290
> # MacOSX/Darwin is just a funny Linux
> #
> ifeq ($(OSTYPE),Darwin)
> OSTYPE = darwin
> endif
>
> ifeq ($(OSTYPE),darwin)
> OS_DIR = darwin
> OSFLAGS = -DOS_LINUX -DOS_DARWIN -DHAVE_STRLCPY -fPIC -Wno-unused-function
> LIBS = -lpthread
> SPECIFIC_OS_PRG = $(BIN_DIR)/mlxspeaker
> NEED_RANLIB=1
> NEED_SHLIB=
> endif
>
> #-----------------------
340a363,364
> LIB =$(LIBNAME)
> ifdef NEED_SHLIB
342,344c366,367
< LIB = -lmidas
< # Uncomment this for static linking of midas executables
< #LIB = $(LIBNAME)
---
> LIB = $(SHLIB)
> endif
351c374
< $(LIB_DIR)/fal.o $(PROGS)
---
> $(LIB_DIR)/fal.o $(PROGS)
431a455,457
> ifdef NEED_RANLIB
> ranlib $@
> endif
432a459
> ifdef NEED_SHLIB
435a463
> endif
Index: include/midas.h
===================================================================
RCS file: /usr/local/cvsroot/midas/include/midas.h,v
retrieving revision 1.126
diff -r1.126 midas.h
464c464
< #if defined(OS_LINUX) || defined(OS_OSF1) || defined(OS_ULTRIX) || defined(OS_FREEBSD) || defined(OS_SOLARIS) || defined(OS_IRIX)
---
> #if defined(OS_LINUX) || defined(OS_OSF1) || defined(OS_ULTRIX) || defined(OS_FREEBSD) || defined(OS_SOLARIS) || defined(OS_IRIX) || defined(OS_DARWIN)
534a535,544
> #endif
>
> /* need system-dependant thread type */
> #if defined(OS_WINNT)
> typedef HANDLE midas_thread_t;
> #elif defined(OS_UNIX)
> #include <pthread.h>
> typedef pthread_t midas_thread_t;
> #else
> typedef INT midas_thread_t;
Index: include/midasinc.h
===================================================================
RCS file: /usr/local/cvsroot/midas/include/midasinc.h,v
retrieving revision 1.11
diff -r1.11 midasinc.h
50a51
> #include <assert.h>
157d157
< #include <sys/mount.h>
163a164,165
> #ifdef OS_DARWIN
> #else
164a167
> #endif
166a170,172
> #ifdef OS_DARWIN
> #include <util.h>
> #else
167a174
> #endif
Index: include/msystem.h
===================================================================
RCS file: /usr/local/cvsroot/midas/include/msystem.h,v
retrieving revision 1.37
diff -r1.37 msystem.h
719,720c719,720
< INT EXPRT ss_thread_create(INT(*func) (void *), void *param);
< INT EXPRT ss_thread_kill(INT thread_id);
---
> midas_thread_t EXPRT ss_thread_create(INT(*func) (void *), void *param);
> INT EXPRT ss_thread_kill(midas_thread_t thread_id);
721a722
> INT ss_timezone(void);
Index: src/mhttpd.c
===================================================================
RCS file: /usr/local/cvsroot/midas/src/mhttpd.c,v
retrieving revision 1.262
diff -r1.262 mhttpd.c
6983c6983
< x_act = (int) floor((double) (xmin - timezone) / label_dx) * label_dx + timezone;
---
> x_act = (int) floor((double) (xmin - ss_timezone()) / label_dx) * label_dx + ss_timezone();
6995,6996c6995,6996
< if ((x_act - timezone) % major_dx == 0) {
< if ((x_act - timezone) % label_dx == 0) {
---
> if ((x_act - ss_timezone()) % major_dx == 0) {
> if ((x_act - ss_timezone()) % label_dx == 0) {
Index: src/system.c
===================================================================
RCS file: /usr/local/cvsroot/midas/src/system.c,v
retrieving revision 1.78
diff -r1.78 system.c
306a307,310
> #ifdef OS_UNIX
> #include <sys/mount.h>
> #endif
>
895c899
< INT thread handle
---
> INT thread handle
914c918
< return (int) hThread;
---
> return hThread;
1653c1657
< thread_id = ss_thread_spawn((void *) taskWatch, &tsWatch);
---
> midas_thread_t thread_id = ss_thread_create((void *) taskWatch, &tsWatch);
1662c1666
< thread_id = ss_thread_spawn((void *) taskWatch, pDevice);
---
> midas_thread_t thread_id = ss_thread_create((void *) taskWatch, pDevice);
1673c1677
< INT ss_thread_create(INT(*thread_func) (void *), void *param)
---
> midas_thread_t ss_thread_create(INT(*thread_func) (void *), void *param)
1675c1679
< #ifdef OS_WINNT
---
> #if defined(OS_WINNT)
1689,1690c1693
< #endif /* OS_WINNT */
< #ifdef OS_MSDOS
---
> #elif defined(OS_MSDOS)
1694,1695c1697
< #endif /* OS_MSDOS */
< #ifdef OS_VMS
---
> #elif defined(OS_VMS)
1699c1701
< #endif /* OS_VMS */
---
> #elif defined(OS_VXWORKS)
1701d1702
< #ifdef OS_VXWORKS
1719d1719
< #endif /* OS_VXWORKS */
1721c1721,1722
< #ifdef OS_UNIX
---
> #elif defined(OS_UNIX)
>
1728c1729,1730
< #endif /* OS_UNIX */
---
>
> #endif
1738c1740
< thread_id = ss_thread_create((void *) taskWatch, pDevice);
---
> midas_thread_t thread_id = ss_thread_create((void *) taskWatch, pDevice);
1749c1751
< INT ss_thread_kill(INT thread_id)
---
> INT ss_thread_kill(midas_thread_t thread_id)
1751c1753
< #ifdef OS_WINNT
---
> #if defined(OS_WINNT)
1755c1757
< status = TerminateThread((HANDLE) thread_id, 0);
---
> status = TerminateThread(thread_id, 0);
1759,1760c1761
< #endif /* OS_WINNT */
< #ifdef OS_MSDOS
---
> #elif defined(OS_MSDOS)
1764,1765c1765
< #endif /* OS_MSDOS */
< #ifdef OS_VMS
---
> #elif defined(OS_VMS)
1769c1769
< #endif /* OS_VMS */
---
> #elif defined(OS_VXWORKS)
1771d1770
< #ifdef OS_VXWORKS
1773d1771
<
1775d1772
<
1777d1773
< #endif /* OS_VXWORKS */
1779,1782c1775
< #ifdef OS_UNIX
< INT status;
<
< status = pthread_kill((pthread_t) thread_id, SIGKILL);
---
> #elif defined(OS_UNIX)
1783a1777,1778
> INT status;
> status = pthread_kill(thread_id, SIGKILL);
1785c1780,1781
< #endif /* OS_UNIX */
---
>
> #endif
2339c2335
< #ifdef OS_WINNT
---
> #if defined(OS_WINNT)
2356,2357c2352,2358
< #endif
< #ifdef OS_UNIX
---
> #elif defined(OS_DARWIN)
>
> assert(!"ss_settime() is not supported");
> /* not reached */
> return SS_NO_DRIVER;
>
> #elif defined(OS_UNIX)
2361,2362c2362
< #endif
< #ifdef OS_VXWORKS
---
> #elif defined(OS_VXWORKS)
2411a2412,2438
> INT ss_timezone()
> /********************************************************************\
>
> Routine: ss_timezone
>
> Purpose: Returns what?!?
>
> Input:
> none
>
> Output:
> what the heck does it return?!?
>
> Function value:
> INT what is it?!?
>
> \********************************************************************/
> {
> #ifdef OS_DARWIN
> return 0;
> #else
> return timezone; /* on Linux, comes from "#include <time.h>". What is it ?!? */
> #endif
> }
>
>
> /*------------------------------------------------------------------*/
4850c4877
< INT status;
---
> #if defined(OS_DARWIN)
4852c4879,4883
< #ifdef OS_UNIX
---
> return 0;
>
... 14 more lines ...
|
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;
}
|
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. |
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 |
68
|
14 Jan 2004 |
Stefan Ritt | | First try- midas on darwin/macosx | Great, I got already questions about MacOSX support...
Once it's working, you should commit the changes. But take into account that using "//" for
comments might cause problems for the VxWorks compiler (talk to Pierre about that!).
> A few hard problems:
> - namespace pollution by Apple- they #define ALIGN in system headers, colliding with ALIGN
> in midas.h. I was amazed that the two are almost identical, but MIDAS ALIGN aligns to 8
> bytes, while Apple does 4 bytes. ALIGN is used all over the place and I am not sure how to
> reconcile this.
You can rename ALIGN to ALIGN8 all over the place.
> - "timezone" in mhttpd.c. On linux, it's an "int", on darwin, it's a function. What gives?
Wrap it into a function get_timezone(). Under linux, just return "timezone", under OSX,
return timezone() via conditional compiling.
> - building libmidas.a requires running ranlib
> - building libmidas.so requires unknown macosx specific magic.
I guess we should foget for now about the shared libraries (Mac people anyhow have too much
money so they can affort additional RAM (;-) ), but building the static library is mandatory. |
67
|
14 Jan 2004 |
Konstantin Olchanski | | First try- midas on darwin/macosx | While watching "The Wizard of Oz", the greatest movie ever made, I took a shot at building
midas on my macosx computer. After stumbling on a few small and on a few hard problems, I
built almost everything. However, odb does not work- some further debugging is in order.
Anyway, the easy problems are:
- a few missing header files: pty.h, sys/vfs.h, malloc.h
- a few missing features in system.c (stime(), "get tape position")
- /usr/include/string.h already has strlcpy() & co.
- dbg_malloc() has inconsistent prototypes (size_t vs unsigned int)
- for reasons unknown, PVM is #defined. This flushed a bug in mana.c
A few hard problems:
- namespace pollution by Apple- they #define ALIGN in system headers, colliding with ALIGN
in midas.h. I was amazed that the two are almost identical, but MIDAS ALIGN aligns to 8
bytes, while Apple does 4 bytes. ALIGN is used all over the place and I am not sure how to
reconcile this.
- "timezone" in mhttpd.c. On linux, it's an "int", on darwin, it's a function. What gives?
- building libmidas.a requires running ranlib
- building libmidas.so requires unknown macosx specific magic.
For your enjoyment, the "cvs diff" is attached. The resulting code is known to not work.
K.O. |
Attachment 1: xxx
|
? .ALARM.SHM
? .ELOG.SHM
? .ODB.SHM
? .SYSMSG.SHM
? darwin
? midas.log
? xx
? xxx
Index: Makefile
===================================================================
RCS file: /usr/local/cvsroot/midas/Makefile,v
retrieving revision 1.50
diff -r1.50 Makefile
0a1
>
218a220,224
> #
> # Uncomment the next line to build the midas shared library
> #
> NEED_SHLIB=1
>
268a275,290
> # MacOSX/Darwin is just a funny Linux
> #
> ifeq ($(OSTYPE),Darwin)
> OSTYPE = darwin
> endif
>
> ifeq ($(OSTYPE),darwin)
> OS_DIR = darwin
> OSFLAGS = -DOS_LINUX -DOS_DARWIN -DHAVE_STRLCPY -fPIC -Wno-unused-function
> LIBS = -lpthread
> SPECIFIC_OS_PRG = $(BIN_DIR)/mlxspeaker
> NEED_RANLIB=1
> NEED_SHLIB=
> endif
>
> #-----------------------
340a363,364
> LIB =$(LIBNAME)
> ifdef NEED_SHLIB
342,344c366,367
< LIB = -lmidas
< # Uncomment this for static linking of midas executables
< #LIB = $(LIBNAME)
---
> LIB = $(SHLIB)
> endif
351c374
< $(LIB_DIR)/fal.o $(PROGS)
---
> $(LIB_DIR)/fal.o $(PROGS)
431a455,457
> ifdef NEED_RANLIB
> ranlib $@
> endif
432a459
> ifdef NEED_SHLIB
435a463
> endif
Index: include/midas.h
===================================================================
RCS file: /usr/local/cvsroot/midas/include/midas.h,v
retrieving revision 1.126
diff -r1.126 midas.h
464c464
< #if defined(OS_LINUX) || defined(OS_OSF1) || defined(OS_ULTRIX) || defined(OS_FREEBSD) || defined(OS_SOLARIS) || defined(OS_IRIX)
---
> #if defined(OS_LINUX) || defined(OS_OSF1) || defined(OS_ULTRIX) || defined(OS_FREEBSD) || defined(OS_SOLARIS) || defined(OS_IRIX) || defined(OS_DARWIN)
534a535,544
> #endif
>
> /* need system-dependant thread type */
> #if defined(OS_WINNT)
> typedef HANDLE midas_thread_t;
> #elif defined(OS_UNIX)
> #include <pthread.h>
> typedef pthread_t midas_thread_t;
> #else
> typedef INT midas_thread_t;
Index: include/midasinc.h
===================================================================
RCS file: /usr/local/cvsroot/midas/include/midasinc.h,v
retrieving revision 1.11
diff -r1.11 midasinc.h
50a51
> #include <assert.h>
157d157
< #include <sys/mount.h>
163a164,165
> #ifdef OS_DARWIN
> #else
164a167
> #endif
166a170,172
> #ifdef OS_DARWIN
> #include <util.h>
> #else
167a174
> #endif
Index: include/msystem.h
===================================================================
RCS file: /usr/local/cvsroot/midas/include/msystem.h,v
retrieving revision 1.37
diff -r1.37 msystem.h
719,720c719,720
< INT EXPRT ss_thread_create(INT(*func) (void *), void *param);
< INT EXPRT ss_thread_kill(INT thread_id);
---
> midas_thread_t EXPRT ss_thread_create(INT(*func) (void *), void *param);
> INT EXPRT ss_thread_kill(midas_thread_t thread_id);
721a722
> INT ss_timezone(void);
Index: src/mhttpd.c
===================================================================
RCS file: /usr/local/cvsroot/midas/src/mhttpd.c,v
retrieving revision 1.262
diff -r1.262 mhttpd.c
6983c6983
< x_act = (int) floor((double) (xmin - timezone) / label_dx) * label_dx + timezone;
---
> x_act = (int) floor((double) (xmin - ss_timezone()) / label_dx) * label_dx + ss_timezone();
6995,6996c6995,6996
< if ((x_act - timezone) % major_dx == 0) {
< if ((x_act - timezone) % label_dx == 0) {
---
> if ((x_act - ss_timezone()) % major_dx == 0) {
> if ((x_act - ss_timezone()) % label_dx == 0) {
Index: src/system.c
===================================================================
RCS file: /usr/local/cvsroot/midas/src/system.c,v
retrieving revision 1.78
diff -r1.78 system.c
306a307,310
> #ifdef OS_UNIX
> #include <sys/mount.h>
> #endif
>
895c899
< INT thread handle
---
> INT thread handle
914c918
< return (int) hThread;
---
> return hThread;
1653c1657
< thread_id = ss_thread_spawn((void *) taskWatch, &tsWatch);
---
> midas_thread_t thread_id = ss_thread_create((void *) taskWatch, &tsWatch);
1662c1666
< thread_id = ss_thread_spawn((void *) taskWatch, pDevice);
---
> midas_thread_t thread_id = ss_thread_create((void *) taskWatch, pDevice);
1673c1677
< INT ss_thread_create(INT(*thread_func) (void *), void *param)
---
> midas_thread_t ss_thread_create(INT(*thread_func) (void *), void *param)
1675c1679
< #ifdef OS_WINNT
---
> #if defined(OS_WINNT)
1689,1690c1693
< #endif /* OS_WINNT */
< #ifdef OS_MSDOS
---
> #elif defined(OS_MSDOS)
1694,1695c1697
< #endif /* OS_MSDOS */
< #ifdef OS_VMS
---
> #elif defined(OS_VMS)
1699c1701
< #endif /* OS_VMS */
---
> #elif defined(OS_VXWORKS)
1701d1702
< #ifdef OS_VXWORKS
1719d1719
< #endif /* OS_VXWORKS */
1721c1721,1722
< #ifdef OS_UNIX
---
> #elif defined(OS_UNIX)
>
1728c1729,1730
< #endif /* OS_UNIX */
---
>
> #endif
1738c1740
< thread_id = ss_thread_create((void *) taskWatch, pDevice);
---
> midas_thread_t thread_id = ss_thread_create((void *) taskWatch, pDevice);
1749c1751
< INT ss_thread_kill(INT thread_id)
---
> INT ss_thread_kill(midas_thread_t thread_id)
1751c1753
< #ifdef OS_WINNT
---
> #if defined(OS_WINNT)
1755c1757
< status = TerminateThread((HANDLE) thread_id, 0);
---
> status = TerminateThread(thread_id, 0);
1759,1760c1761
< #endif /* OS_WINNT */
< #ifdef OS_MSDOS
---
> #elif defined(OS_MSDOS)
1764,1765c1765
< #endif /* OS_MSDOS */
< #ifdef OS_VMS
---
> #elif defined(OS_VMS)
1769c1769
< #endif /* OS_VMS */
---
> #elif defined(OS_VXWORKS)
1771d1770
< #ifdef OS_VXWORKS
1773d1771
<
1775d1772
<
1777d1773
< #endif /* OS_VXWORKS */
1779,1782c1775
< #ifdef OS_UNIX
< INT status;
<
< status = pthread_kill((pthread_t) thread_id, SIGKILL);
---
> #elif defined(OS_UNIX)
1783a1777,1778
> INT status;
> status = pthread_kill(thread_id, SIGKILL);
1785c1780,1781
< #endif /* OS_UNIX */
---
>
> #endif
2339c2335
< #ifdef OS_WINNT
---
> #if defined(OS_WINNT)
2356,2357c2352,2358
< #endif
< #ifdef OS_UNIX
---
> #elif defined(OS_DARWIN)
>
> assert(!"ss_settime() is not supported");
> /* not reached */
> return SS_NO_DRIVER;
>
> #elif defined(OS_UNIX)
2361,2362c2362
< #endif
< #ifdef OS_VXWORKS
---
> #elif defined(OS_VXWORKS)
2411a2412,2438
> INT ss_timezone()
> /********************************************************************\
>
> Routine: ss_timezone
>
> Purpose: Returns what?!?
>
> Input:
> none
>
> Output:
> what the heck does it return?!?
>
> Function value:
> INT what is it?!?
>
> \********************************************************************/
> {
> #ifdef OS_DARWIN
> return 0;
> #else
> return timezone; /* on Linux, comes from "#include <time.h>". What is it ?!? */
> #endif
> }
>
>
> /*------------------------------------------------------------------*/
4850c4877
< INT status;
---
> #if defined(OS_DARWIN)
4852c4879,4883
< #ifdef OS_UNIX
---
> return 0;
>
... 14 more lines ...
|
78
|
06 Jan 2004 |
Stefan Ritt | | Poll about default indent style | Ok, taking all comments so far into account, I conclude adopting the ROOT
coding style would be best for us. So I put
indent:
find . -name "*.[hc]" -exec indent -kr -nut -i3 {} \;
Into the makefile. Hope everybody is happy now (;-))) |
77
|
01 Jan 2004 |
Konstantin Olchanski | | Poll about default indent style | > I don't feel a strong need of giving up a "-i2"...
I am comfortable with the current MIDAS styling convention and I would rather not
have yet another private religious war over the right location for the curley braces.
If we are to consider changing the MIDAS coding convention, I urge all and sundry
to read the ROOT coding convention, as written by Rene Brun and Fons Rademakers at
http://root.cern.ch/root/Conventions.html. The ROOT people did their homework, they
did read the literature and they produced a well considered and well argumented style.
Also, while there, do read the Taligent documentation- by far, one of the most
coherent manuals to C++ programming style.
K.O. |
76
|
18 Dec 2003 |
Stefan Ritt | | Poll about default indent style | Hi Paul,
I agree with you that a nesting level of more than 4-5 is a bad thing, but I
believe that throughout the midas code, this level is not exceeded (my poor
mind also does not hold more than 5 things (;-) ). An indent level of 8 columns
alone does hot force you too much in not extending the nesting level. I have
seen code which does that, so there are nesting levels of 8 and more, which
ends up that the code is smashed to the right side of the screen, where each
statement is broken into many line since each line only holds 10 or 20
characters. All the nice real estate on the left side of the scree is lost.
So having said that, I don't feel a strong need of giving up a "-i2", since the
midas code does not contain deep nesting levels and hopefully will never have.
In my opinion, a small indent level makes more use of your screen space, since
you do not have a large white area at the left. A typical nesting level is 3-4,
which causes already 32 blank charactes at the left, or 1/3 of your screen,
just for nothing. It will lead to more lines (even with -l90), so people have
to scroll more.
What do others think (Pierre, Konstantin, Renee) ? |
75
|
18 Dec 2003 |
Paul Knowles | | Poll about default indent style | Hi Stefan,
> once and forever, I am considering using the "indent" program which comes
> with every linux installation. Running indent regularly on all our code
> ensures a consistent look.
I think this can be called a Good Thing.
> The "-kr" style does the standard K&R style,
> but used tabs (which is not good), and does a 4-column
> indention which is I think too much. So I would propose
> following flags:
> indent -kr -nut -i2 -di8 -bad <filename.c>
(some of this is a repeat from an earlier mail to SR):
You might also want a -l90 for a longer line length than 75
characters. K&R style with indentation from 5 to 8 spaces
is a good indicator of complexity: as soon as 40 characters
of code wind up unreadably squashed to the right of the
screen, you have to refactor to have less indentation
levels. This means you wind up rolling up the inner parts
of deeply nested conditionals or loops as separate
functions, making the whole code easier to understand.
I think that setting -i2 is ``going around the problem''
of deep nesting. If you really need to keep the indentation
tabs less than 4 (8 is ideal) because your code is falling off the
right edge of the screen, you are indented too deeply. Why do
I say that? There is the famous ``7+-1'' idea that you can hold
in you head only 7 ideas (give or take one) at any time. I'm not
that smart and I top out at about 5: So for example, a conditional
in a loop in a conditional in a switch is about as deep a level
of nesting as I can easily understand (remember that I also have
to hold the line i'm working on as well): that's 4 levels, plus one for the
function itself and we are at 40 characters away from the right edge
of the screen using -i8 and have some 40 characters available for writing code
(how often is a line of code really longer than about 40 characters?).
On top of that, the indentation is easily seen so you know immediately
wheather you are at the upper conditional, or inner conditional. A -i2
just doesn't make the difference big enough. -i5 is a happy balance
with enough visual clue as to the indentation level, but leaves you 50
to 60 characters for the code line itself.
However, if you are indenting very deeply, then the poor reader can't hold
on to the context: there are more than 6 or 7 things to keep in mind.
In those cases, roll up the inner levels as a separate function and
call it that way. The inner complexity of the nested statements gets
nicely abstracted and then dumb people like me can understand what
you are doing.
So, in brief: indent is a good idea, and -in with n>=4 will be best.
I don't think -i2 will lend itself to making the code so much easier
to read.
thanks for listening.
.p. |
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.
|
|