ID |
Date |
Author |
Topic |
Subject |
95
|
20 Nov 2003 |
Stefan Ritt | | cannot shutdown defunct clients | > INT == "int", wraparound in 1 month
> DWORD == "unsigned int", wraparound in 2 months
>
> should we make it the 64-bit "long long" (or C98's "int64_t")?
Won't work on all supported compilers. The point is that DWORD wraps around in
2 months, but the difference of two DWORDs is alywas positive, never negative
like you had it. We only have to distinguish if the difference of the current
time (im ms) minus the last_activity of a client is larget than the timeout,
typically 10 seconds or so. If you have a wraparound on 32-bit DWORD, the
difference is still ok. Like
current "time" : 0x0000 0100
last_activity: 0xFFFF FF00
then current_time - last_activity = 0x00000100 - 0xFFFFFF00 = 0x00000200 if
calculated with 32-bit values. |
100
|
21 Nov 2003 |
Stefan Ritt | | Revised MVMESTD | Thanks for your contribution. Let me try to map your functionality to mvmestd calls:
> A) The VMIC vme_slave_xxx() options are not considered.
We could maybe do that through mvme_mmap(SLAVE, ...) instead of mvme_mmap(MASTER, ...)
> B) The interrupt handling can certainly match the 4 entries required in the user frontend
> code i.e. Attach, Detach, Enable, Disable.
vmve_ioctl(VME_IOCTL_INTR_ATTACHE/DETACH/ENABLE/DISABLE, func())
> I don't understand your argument that the handle should be hidden. In case of multiple
> interfaces, how do you refer to a particular one if not specified?
> The following scheme does require a handle for refering to the proper (device AND window).
Four reasons for that:
1) For the SBS/Bit3, you need a handle for each address mode. So if I have two crates (and I do in our
current experiment), and have to access modules in A16, A24 and A32 mode, I need in total 6 handles.
Sometimes I mix them up by mistake, and wonder why I get bus errors.
2) Most installations will only have single crates (as your VMIC). So if there is only one crate, why
bother with a handle? If you have hunderds of accesses in your code, you save some redundant typing work.
3) A handle is usually kept global, which is considered not good coding style.
4) Our MCSTD and MFBSTD functions also do not use a handle, so people used to those libraries will find it
more natural not to use one.
> 1 ) deviceHandle = vme_init(int devNumber);
> Even though the VMIC doesn't deal with multiple devices,
> the SIS/PCI does and needs to init on a specific PCI card.
> Internally:
> opening of the device (/dev/sisxxxx_1) (ignored in case of VMIC).
> Possible including a mapping to a default VME region of default size with default AM
> (VMIC :16MB, A24). This way in a single call you get a valid handle for full VME access
> in A24 mode. Needs to be elaborate this option. But in principle you need to declare the
> VME region that you want to work on (vme_map).
Just vme_init(); (like fb_init()).
This function takes the first device, opens it, and stores the handle internally. Sets the AM to a default
value, and creates a mapping table which is initially empty or mapped to a default VME region. If one wants
to access a secondary crate, one does a vme_ioctl(VME_IOCTL_CRATE_SET, 2), which opens the secondary crate,
and stores the new handle in the internal table if applicable.
> 2) mapHandle = vme_map(int deviceHandle, int vmeAddress, int am, int size);
> Return a mapHandle specific to a device and window. The am has to be specified.
> What ever are the operation to get there, the mapHandle is a reference to thas setting.
> It could just fill a map structure.
> Internally:
> WindowHandle[deviceHandle] = vme_master_create(BusHandle[deviceHandle], ...
> WindowPtr[WindowHandle] = vme_master_window(BusHandle[deviceHandle]
> , WindowHandle[deviceHandle]...
The best would be if a mvme_read(...) to an unmapped region would automatically (internally) trigger a
vme_map() call, and store the WindowHandle and WindowPtr internally. The advantage of this is that code
written for the SIS for example (which does not require this kind of mapping) would work without change
under the VMIC. The disadvantage is that for each mvme_read(), the code has to scan the internal mapping
table to find the proper window handle. Now I don't know how much overhead this would be, but I guess a
single for() loop over a couple of entries in the mapping table is still faster than a microsecond or so,
thus making it negligible in a block transfer.
> 3) vme_setmode(mapHandle, const int DATA_SIZE, const int AM
> , const BOOL ENA_DMA, const BOOL ENA_FIFO);
> Mainly used for the vme_block_read/write. Define for following read the data size and
> am in case of DMA (could use orther DMA mode than window definition for optimal
> transfer).
>
> Predefine the mode of access:
> DATA_SIZE : D8, D16, D32
> AM : A16, A24, A32, etc...
> enaDMA : optional if available.
> enaFIFO : optional for block read for autoincrement source pointer.
>
> Remark:
> PAA- I can imagine this function to be a vme_ioctl (int mapHandle, int *param)
> such that extension of functionality is possible. But by passing cons int
> arguments, the optimizer is able to substitute and reduce the internal code.
Right. mvme_ioctl(VME_IOCTL_AMOD_SET/DSIZE_SET/DMA_SET/AUTO_INCR_SET, ...)
> uint_8Value = vme_readD8 (int mapHandle, uint_64 vmeSrceOffset)
> uint_16Value = vme_readD16 (int mapHandle, uint_64 vmeSrceOffset)
> uint_32Value = vme_readD32 (int mapHandle, uint_64 vmeSrceOffset)
> Single VME read access. In the VMIC case, this access is always through mapping.
> Value = *(WindowPtr[WindowHandle] + vmeSrceOffset)
> or
> Value = *(WindowStruct->WindowPtr[WindowHandle] + vmeSrceOffset)
mvme_read(*dst, DWORD vme_addr, DWORD size); would cover this in a single call. Note that the SIS for
example does not have memory mapping, so if one consistently uses mvme_read(), it will work on both
architectures. Again, this takes some overhead. Consider for example a possible VMIC implementation
mvme_read(char *dst, DWORD vme_addr, DWORD size)
{
for (i=0 ; table[i].valid ; i++)
{
if (table[i].start >= vme_addr && table[i].end < vme_addr+size)
break;
}
if (!table[i].valid)
{
vme_master_crate(...)
table[i].window_handle = vme_master_window(...)
}
if (size == 2)
mvme_ioctl(VME_IOCTL_DSIZE_SET, D16);
else if (size == 1)
mvme_ioctl(VME_IOCTL_DSIZE_SET, D8);
memcpy(dst, table[i].window_handle + vme_addr - table[i].start, size);
}
Note this is only some rough code, would need more checking etc. But you see that for each access the for()
loop has to be evaluated. Now I know that for the SBS/Bit3 and for the SIS a single VME access takes
~0.5us. So the for() loop could be much faster than that. But one has to try. If one experiment needs the
ultimate speed, it can use the native VMIC API, but then looses the portability. I'm not sure if one needs
the automatic DSIZE_SET, maybe it works without.
> status = vme_writeD8 (int mapHandle, uint_64 vmeSrceOffset, uint_8 Value)
> status = vme_writeD16 (int mapHandle, uint_64 vmeSrceOffset, uint_16 Value)
> status = vme_writeD32 (int mapHandle, uint_64 vmeSrceOffset, uint_32 Value)
> Single VME write access.
Dito. mvme_write(void *dst, DWORD vme_addr, DWORD size);
> nBytes = vme_block_read(mapHandle, char * pDest, uint_64 vmeSrceOffset, int size);
> Multiple read access. Can be done through standard do loop or DMA if available.
> nBytes < 0 : error
> Incremented pDest = (pDest + nBytes); Don't need to pass **pDest for autoincrement.
vmve_ioctl(VME_IOCTL_DMA_SET, TRUE);
n = mvme_read(char *pDest, DWORD vmd_addr, DWORD size);
> nBytes = vme_block_write(mapHandle, uint_64 vmeSrceOffset, char *pSrce, int size);
> Multiple write access.
> nBytes < 0 : error
> Incremented pSrce = (pSrce + nBytes); Don't need to pass **pSrce for autoincrement.
Dito.
> 8) status = vme_unmap(int mapHandle)
> Cleanup internal pointers or structure of given mapHandle only.
mvme_unmap(DWORD vme_addr, DWORD size)
Scan through internal table to find handle, then calls vme_unmap(mapHandle);
> 9) status = vme_exit()
> Cleanup deviceHandle and release device.
mvme_exit();
Let me know if this all makes sense to you...
- Stefan |
97
|
24 Nov 2003 |
Stefan Ritt | | cannot shutdown defunct clients | > But there is one problem with "cleanup". It has a hardwired timeout of
> 2 seconds. This is a problem for tasks like lazylogger which set a timeout
> of 60 seconds when moving the tape. So BEWARE, if you issue the "cleanup"
> command, it might kill some clients who have setup their timeout to longer
> than 2 seconds.
>
> I have asked Stefan to change this before. He said that, to be effective,
> the timeout value used for "cleanup" has to be rather short.
> One possibility, would be to allow for a user entered "cleanup" timeout.
> The default could stay at 2 seconds.
I changed the behaviour of cleanup by adding an extra parameter
ignore_timeout to cm_cleanup(). Now, in ODBEdit, a "clanup" obeys the
timeout set by the clients. The problem with that is if the logger crashes
for example, and it's timeout is set o 5 min., it cannot be clean-up'ed any
more for the next five minutes, and therefor not be restarted wasting
precious beam time. That's why I hard-wired originally the "cleanup" timout
to 2 sec. Now I added a flag "-f" to the ODBEdit cleanup command which works
in the old fashion with a 2 sec. timeout. So a "cleanup" alone won't kill a
looger which currently rewinds a tape or so, but a "cleanup -f" does.
I also changed internal timeouts from INT to DWORD, which should fix the
problem Konstantin reported recently (re-starting an experiment after
several weeks). New changes are commited, but I only did basic tests. So
please try the new code and tell me if there is any problem.
- Stefan |
90
|
30 Nov 2003 |
Stefan Ritt | | bad call to cm_cleanup() in fal.c | > fal.c does not compile: it calls cm_cleanup() with one argument when there
> should be two arguments. K.O.
Fixed and committed. |
85
|
30 Nov 2003 |
Stefan Ritt | | Implementation of db_check_record() | Fixed and committed. Can you check if it's working? |
88
|
01 Dec 2003 |
Stefan Ritt | | delete key followed by create record leads to empty structure in experim.h | > I have noticed a problem with deleting a key to an array in odb, then
> recreating the record as in the code below. The record is recreated
> successfully, but when viewing it with mhttpd, a spurious blank line
> (coloured orange) is visible, followed by the rest of the data as normal.
>
> db_create_record(hDB,0,"/Equipment/Cycle_scalers/Settings/",strcomb(type1_str));
> }
> else {
> exp_mode = 2; /* TDmusr types - noscans */
> status =
> db_create_record(hDB,0,"/Equipment/Cycle_scalers/Settings/",strcomb(type2_str));
> }
The first problem is that the db_create_record has a trailing "/" in the key name
after Settings. This causes the (empty) subsirectory which causes your trouble.
Simple removing it fixes the problem. I agree that this is not obvious, so I
added some code in db_create_record() which removes such a trailing slash if
present. New version under CVS.
Second, the db_create_record() call is deprecated. You should use the new
function db_check_record() instead, and remove your db_delete_key(). This avoids
possible ODB trouble since the structure is not re-created each time, but only
when necessary.
- Stefan |
81
|
12 Dec 2003 |
Stefan Ritt | | db_close_record non-local/non-return | Hi Paul,
sorry my late reply, I had to find some time for debugging your problem.
Thank you very much for the detailed description of the problem, I wish all
bug reports would be such elaborate!
You were right that there was a bug in the RPC system. The function
db_remove_open_record() got a new parameter recently, which was not changed
in the RPC call, and caused the mserver side to crash on any
db_close_record() call.
I fixed it and the update is under CVS (http://midas.psi.ch/cgi-
bin/cvsweb/midas/src/). Since you need to update many files, I wonder if I
should enable anonymous CVS read access. Does anybody know how to set this
up using "ssh" as the protocol (via CVS_RSH=ssh)?
Please note that db_close_record() is not necessary as
cm_disconnect_experiment() takes care of this, but having it there does not
hurt. |
79
|
12 Dec 2003 |
Stefan Ritt | | Several small fixes and changes | I committed several small fixes and changes:
- install.txt which mentions explicitly ROOT
- mana.c and the main Makefile which fixes all HBOOK compiler warnings
- mana.c to write an explicit warning if the experiment directoy contains
uppercase letters in the path (HBOOK does not like this and refuses to
read/write histos)
- mserver.c, mrpc.c, odb.c to fix a wrong parameter in
db_remove_open_record() (see previous entry from Paul)
- added experim.h into the dependency of the hbookexpt Makefile |
74
|
15 Dec 2003 |
Stefan Ritt | | Poll about default indent style | Dear all,
there are continuing requests about the C indent style we use in midas. As
you know, the current style does not comply with any standard. It is even
a mixture of styles since code comes from different people. To fix this
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. So I propose (actually the idea came from Paul
Knowles) to put a new section in the midas makefile:
indent:
find . -name "*.[hc]" -exec indent <flags> {} \;
so one can easily do a "make indent". The question is now how the <flags>
should look like. The standard is GNU style, but this deviates from the
original K&R style such that the opening "{" is put on a new line, which I
use but most of you do not. 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>
Please take some of your source code, and format it this way, and let me
know if these flags are a good combination or if you would like to have
anything changed. It should also be checked (->PAA) that this style
complies with the DOC++ system. Once we all agree, I can put it into the
makefile, execute it and commit the newly formatted code for the whole
source tree. |
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.
|
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) ? |
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 (;-))) |
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. |
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. |
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 |
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. |
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). |
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;
}
|
65
|
30 Mar 2004 |
Stefan Ritt | | elog fixes | Thanks for fixing these long lasting bugs. The code is much cleaner now, please
commit it. |
63
|
30 Apr 2004 |
Stefan Ritt | | mhttpd | > I am setting up a new experiment and I added a "comment" field to "/
> Experiment/Edit on start". When I start the run, I see this field, but I
> cannot enter anything: the HTML "maxlength" is zero (or 1?). I traced this
> to mhttpd.c: if (this is a string) maxlength = key.item_size. But what is
> key.item_size for a string? The current length? If so, how do I enter a
> string that is longer than the current one (zero in case I start from
> scratch). I am stumped! K.O.
Your problem is that you created a ODB string with zero length. If you do this
through ODBEdit, a default length of 32 is used:
[local:Test:S]Edit on start>cr string Comment
String length [32]:
[local:Test:S]Edit on start>ls -l
Key name Type #Val Size Last Opn Mode Value
---------------------------------------------------------------------------
Comment STRING 1 32 2s 0 RWD
[local:Test:S]Edit on start>
which then results in a maxlength of 32 as well during run start. I presume
you used mhttpd itself to create the string. Trying to reporduce this, I found
that mhttpd creates strings with zero length. I will fix this soon. Until
then, use ODBEdit to create your strings. |
|