Quick Start - Top - Utilities
This section refers to the Midas built-in capabilities. The following sections describe in more details the essential aspect of each feature starting from the frontend to the Electronic Logbook.
The run transition sequence has been modified since Midas version 1.9.5. The new scheme utilize transition sequence level which provides the user a full control of the sequencing of any Midas client.
Midas defines 3 states of Data acquistion: STOPPED, PAUSED, RUNNING
These 3 states require 4 transitions : TR_START, TR_PAUSE , TR_RESUME, TR_STOP
Any Midas client can request notification for run transition. This notification is done by registering to the system for a given transition ( cm_register_transition() ) by specifying the transition type and the sequencing number (1 to 1000). Multiple registration to a given transition can be requested. This last option permits for example to invoke two callback functions prior and after a given transition such as the start of the logger.
my_application.c
INT before_logger(INT run_number, char *error)
{
printf("Initialize ... before the logger gets the Start Transition");
...
return CM_SUCCESS;
}
INT after_logger(INT run_number, char *error)
{
printf("Log initial info to file... after logger gets the Start Transition");
...
return CM_SUCCESS;
}
INT main()
{
...
cm_register_transition(TR_START, before_logger, 100);
cm_register_transition(TR_START, after_logger, 300);
...
}
By Default the following sequence numbers are used:
- Frontend : TR_START: 500, TR_PAUSE: 500, TR_RESUME: 500,TR_STOP: 500
- Analyzer : TR_START: 500, TR_PAUSE: 500, TR_RESUME: 500,TR_STOP: 500
- Logger : TR_START: 200, TR_PAUSE: 500, TR_RESUME: 500,TR_STOP: 800
- EventBuilder : TR_START: 300, TR_PAUSE: 500, TR_RESUME: 500,TR_STOP: 700
The sequence number appears into the ODBedit under /System/Clients/
[local:midas:S]Clients>ls -lr
Key name Type #Val Size Last Opn Mode Value
---------------------------------------------------------------------------
Clients DIR
1832 DIR <------------ Frontend 1
Name STRING 1 32 21h 0 R ebfe01
Host STRING 1 256 21h 0 R pierre2
Hardware type INT 1 4 21h 0 R 42
Server Port INT 1 4 21h 0 R 2582
Transition START INT 1 4 21h 0 R 500
Transition STOP INT 1 4 21h 0 R 500
Transition PAUSE INT 1 4 21h 0 R 500
Transition RESUME INT 1 4 21h 0 R 500
RPC DIR
17000 BOOL 1 4 21h 0 R y
3872 DIR <------------ Frontend 2
Name STRING 1 32 21h 0 R ebfe02
Host STRING 1 256 21h 0 R pierre2
Hardware type INT 1 4 21h 0 R 42
Server Port INT 1 4 21h 0 R 2585
Transition START INT 1 4 21h 0 R 500
Transition STOP INT 1 4 21h 0 R 500
Transition PAUSE INT 1 4 21h 0 R 500
Transition RESUME INT 1 4 21h 0 R 500
RPC DIR
17000 BOOL 1 4 21h 0 R y
2220 DIR <------------ ODBedit doesn't need transition
Name STRING 1 32 42s 0 R ODBEdit
Host STRING 1 256 42s 0 R pierre2
Hardware type INT 1 4 42s 0 R 42
Server Port INT 1 4 42s 0 R 3429
568 DIR <------------ Event Builder
Name STRING 1 32 26s 0 R Ebuilder
Host STRING 1 256 26s 0 R pierre2
Hardware type INT 1 4 26s 0 R 42
Server Port INT 1 4 26s 0 R 3432
Transition START INT 1 4 26s 0 R 300
Transition STOP INT 1 4 26s 0 R 700
2848 DIR <------------ Logger
Name STRING 1 32 5s 0 R Logger
Host STRING 1 256 5s 0 R pierre2
Hardware type INT 1 4 5s 0 R 42
Server Port INT 1 4 5s 0 R 3436
Transition START INT 1 4 5s 0 R 200
Transition STOP INT 1 4 5s 0 R 800
Transition PAUSE INT 1 4 5s 0 R 500
Transition RESUME INT 1 4 5s 0 R 500
RPC DIR
14000 BOOL 1 4 5s 0 R y
The /System/Clients/... tree reflects the system at a given time. If a permanent change of a client sequence number is required, the system call cm_set_transition_sequence() can be used.
Under MIDAS, experiment hardware is structured into "equipment" which refers to a collection of hardware devices such as: a set of high voltage supplies, one or more crates of digitizing electronics like ADCs and TDCs or a set of scaler. On a software point of view, we keep that same equipment term to refer to the mean of collecting the data related to this "hardware equipment". The data from this equipment is then gathered into an "event" and send to the back-end computer for logging and/or analysis.
The frontend program (image) consists of a system framework contained in mfe.c (hidden from the user) and a user part contained in frontend.c . The hardware access is only apparent in the user code.
Several libraries and drivers exist for various bus systems like CAMAC, VME or RS232. They are located in the drivers directory of the MIDAS distribution. Some libraries consist only of a header file, others of a C file plus a header file. The file names usually refer to the manufacturer abbreviation followed by the model number of the device. The libraries are continuously expanding to widen Midas support.
ESONE standard routines for CAMAC are supplied and permit to re-use the frontend code among different platforms as well as different CAMAC hardware interface without the need of modification of the code.
The user frontend code consists of several sections described in order below. Example of frontend code can be found under the ../examples/experiment directory:
- [Global declaration] Up to the User global section the declarations are system wide and should not be removed.
- frontend_name This value can be modified to reflect the purpose of the code.
- frontend_call_loop() Enables the function frontend_loop() to run after every equipment loop.
- display_period defined in millisecond the time interval between refresh of a frontend status display. The value of zero disable the display. If the frontend is started in a background with the display enabled, the stdout should be redirected to the null device to prevent process to hang.
- max_event_size specify the maximum size of the expected event in byte.
- event_buffer_size specify the maximum size of the buffer in byte to be allocated by the system. After these system parameters, the user may add his or her own declarations.
- [Prototype functions] The first group of prototype(7) declare the pre-defined system functions which should be present. The second group defines the user functions associated to the declared equipments. All the fields are described in detailed in the following section.
- [Remark] Each equipment has the option to force itself to run at individual transition time see ro_mode . At transition time the system functions begin_of_run(), end_of_run(), pause_run(), resume_run() runs prior to the equipment functions. This gives the system the chance to take basic action on the transition request (Enable/disable LAM) before the equipment runs. The sequence of operation is the following:
- frontend_init() : Runs once after system initialization, before equipment registration.
- begin_of_run() : Runs after systerm statistics reset, before any other Equipments at each Begining of Run request.
- pause_run(): Runs before any other Equipments at each Run Pause request.
- resume_run(): Runs before any other Equipments at each Run Resume request.
- end_of_run(): Runs before any other Equipments at each End of Run request.
- frontend_exit(): Runs once before Slow Control Equipment exit.
- [Bank definition] Since the introduction of ROOT , the frontend requires to have the definition of the banks in the case you desire to store the raw data in ROOT format. This procedure is equivalent to the bank declaration in the analyzer. In the case the format declared is MIDAS, the example below shows the a structured bank and a standard variable length bank declaration for the trigger bank list. The trigger_bank_list[] is declared in the equipment structure (see Eq_example ).
ADC0_BANK_STR(adc0_bank_str);
BANK_LIST trigger_bank_list[] = {
{"ADC0", TID_STRUCT, sizeof(ADC0_BANK), adc0_bank_str},
{"TDC0", TID_WORD, N_TDC, NULL},
{""},
};
BANK_LIST scaler_bank_list[] = {
{"SCLR", TID_DWORD, N_ADC, NULL},
{""},
};
- [Equipment definition] See The Equipment structure for further explanation.
#undef USE_INT
EQUIPMENT equipment[] = {
{ "Trigger",
{1, 0,
"SYSTEM",
#ifdef USE_INT
EQ_INTERRUPT,
#else
EQ_POLLED,
#endif
LAM_SOURCE(CRATE, LAM_STATION(SLOT_C212)),
"MIDAS",
TRUE,
RO_RUNNING |
RO_ODB,
500,
0,
0,
0,
"", "", ""}
,
read_trigger_event,
NULL, NULL,
trigger_bank_list,
}
,
...
- [frontend_init()] This function run once only at the application startup. Allows hardware checking, loading/setting of global variables, hot-link settings to the ODB etc... In case of CAMAC the standard call can be:
- [begin_of_run()] This function is called for every run start transition. Allows to update user parameter, load/setup/clear hardware. At the exit of this function the acquisition should be armed and ready to test the LAM. In case of CAMAC frontend, the LAM has to be declared to the Crate Controller. The function cam_lam_enable(CRATE, SLOT_IO) is then necessary in order to enable the proper LAM source station. The LAM source station has to also be enabled (F26).
The argument run_number provides the current run number being started. The argument error can be used for returning a message to the system. This string will be logged into the {b midas.log file.
camc(CRATE, SLOT_C212, 0, 9);
camc(CRATE, SLOT_2249A, 0, 9);
camc(CRATE, SLOT_SC2, 0, 9);
camc(CRATE, SLOT_SC3, 0, 9);
camc(CRATE, SLOT_C212, 0, 26);
cam_inhibit_clear(CRATE);
cam_lam_enable(CRATE, SLOT_C212);
camo(CRATE, SLOT_OR1320, 0, 18, 0x0330);
camo(CRATE, SLOT_OR1320, 0, 21, 0x0663);
return SUCCESS;
- [poll_event()] If the equipment definition is EQ_POLLED as an acquisition type, the poll_event() will be called as often as possible over the corresponding poll time (ex:500ms see The Equipment structure) given by each polling equipment. The code below shows a typical CAMAC LAM polling loop. The source corresponds to a bitwise LAM station susceptible to generate LAM for that particular equipement. If the LAM is ORed for several stations and is independent of the equipment, the LAM test can be simplified (see example below)
- [Remark] When multiple LAM sources are specified for a given equipment like: The polling function will pass to the readout function the actual LAM pattern read during the last polling. This pattern is a bitwise LAM station. The content of the pevent will be overwritten. This option allows you to determine which of the stations has been the real source of the LAM.
- [pause_run() / resume_run()] These two functions are called respectively upon "Pause" and "Resume" command. Any code relevant to the upcoming run state can be included. Possible commands when CAMAC is involved can be cam_inhibit_set(CRATE) and cam_inhibit_clear(CRATE). The argument run_number provides the current run number being paused/resumed. The argument error can be used for returning a message to the system. This string will be logged into the midas.log file.
- [end_of_run()] For every "stop run" transition this function is called and provides the opportunity to disable the hardware. In case of CAMAC frontend the LAM should be disabled.
The argument run_number provides the current run number being ended. The argument error can be used for returning a message to the system. This string will be logged into the midas.log file.
camo(CRATE, SLOT_OR1320, 0, 18, 0x0CC3);
camo(CRATE, SLOT_OR1320, 0, 21, 0x0990);
camc(CRATE, SLOT_C212, 0, 26);
cam_lam_disable(CRATE, SLOT_C212);
cam_inhibit_set(CRATE);
- [frontend_exit()] This function runs when the frontend is requested to terminate. Can be used for local statistic collection etc.
To write a frontend program, the user section (frontend.c) has to have an equipment list organized as a structure definition. Here is the structure list for a trigger and scaler equipment from the sample experiment example frontend.c.
#undef USE_INT
EQUIPMENT equipment[] = {
{ "Trigger",
{1, 0,
"SYSTEM",
#ifdef USE_INT
EQ_INTERRUPT,
#else
EQ_POLLED,
#endif
LAM_SOURCE(0,0xFFFFFF),
"MIDAS",
TRUE,
RO_RUNNING |
RO_ODB,
500,
0,
0,
0,
"", "", ""}
,
read_trigger_event,
NULL, NULL,
trigger_bank_list,
}
,
...
- ["trigger","scaler"]: Each equipment has to have a unique equipment name defined under a given node. The name will be the reference name of the equipment generating the event.
- [1, 0]: Each equipment has to be associated to a unique event ID and a trigger mask. Both the event ID and the trigger mask will be part of the event header of that particular equipment. The trigger mask can be modified dynamically by the readout routine to define a sub-event type on an event-by-event basis. This can be used to mix "physics events" (from a physics trigger) and "calibration events" (from a clock for example) in one run and identify them later. Both parameters are declared as 16bit value. If the Trigger mask is used in a single bit-wise mode, only up to 16 masks are possible.
- ["SYSTEM"] After composition of an "equipment", the Midas frontend mfe.c takes over the sending of this event to the "system buffer" on the back-end computer. Dedicated buffer can be specified on those lines allowing a secondary stage on the back-end (Event builder to collect and assemble these events coming from different buffers in order to compose a larger event. In this case the events coming from the frontend are called fragment). In this example both events are placed in the same buffer called "SYSTEM" (default).
- [Remark] If this field is left empty ("") the readout function associated to that equipment will still be performed, but the actual event won't be sent to the buffer. The positive side-effect of that configuration is to allow that particular equipment to be mirrored in the ODB if the RO_ODB is turned on.
- [EQ_xxx] The field specify the type of equipment. It can be of a single type such as EQ_POLLED, EQ_INTERRUPT, EQ_MULTITHREAD, and EQ_SLOW. EQ_POLLED and EQ_MULTITHREAD are similar expect for the polling function which in the case of EQ_MULTITHREAD resides in a separate thread. This new type has been added to take advantage of the multi-core processor and free up CPU for other task than polling.
- [EQ_POLLED] In this mode, the name of the routine performing the trigger check function is defaulted to poll_event(). As polling consists of checking a variable for a true condition, if the loop would be infinite, the frontend would not be able to respond to any network commands. Therefore the loop count is determined when the frontend starts so that it returns after a given time-out if no event is available. This time-out is usually in the order of 500 milliseconds. This flag is mainly used for data acquisition based on a "LAM".
- [EQ_INTERRUPT] For this mode, Midas requires complete configuration and control of the interrupt source. This is provided by an interrupt configuration routine interrupt_configure() that has to be coded by the user in the user section of the frontend code. A pointer to this routine is passed to the system instead of the polling routine. The interrupt configuration routine has the following declaration:
- [EQ_PERIODIC] In this mode the function associated to this equipment is called periodically. No hardware requirements is necessary to trigger the readout function. The "poll" field in the equipment declaration is in this case used for periodicity.
- [EQ_MULTITHREAD] This new equipment type is valid since version 2.0. It implements the multi-threading capability within the frontend code. The polling is performed within a separate thread and uses the ring buffer functions rb_xxx for inter-thread communication.
- [EQ_SLOW] Declare the equipment as a Slow Control equipment. This will enable the call to the idle function part of the class driver.
- [EQ_MANUAL_TRIG] This flag enables the equipment to be triggered by remote procedure call (RPC). If present, the web interface will provide a button for that action.
- [EQ_FRAGMENTED] This flag enables large events (beyond Midas configuration limit) to be handled by the system. This flag requires to have a valid max_event_size_frag variable defined in the user frontend code (frontend.c). The max_event_size variable is used as fragment size in this case. This option is meant to be used in experiments where the event rate is not an issue but the size of the data needs to be extremely large. In any selected case, when the equipment is required to run, a declared function is called doing the actual user required operation. Under the four commands listed above, the user has to implement the adequate hardware operation performing the requested action. In drivers examples can be found on such an interrupt code. See source code such as hyt1331.c, ces8210.c.
- CMD_INTERRUPT_ENABLE: to enable an interrupt
- CMD_INTERRUPT_DISABLE: to disable an interrupt
- CMD_INTERRUPT_INSTALL: to install an interrupt callback routine at address adr.
- CMD_INTERRUPT_DEINSTALL: to de-install an interrupt.
- [EQ_EB] This flag identifies the equipment as a fragment event and should be ored with the EQ_POLLED in order to be identified by the Event_Builder.
- [LAM_SOURCE(0,0xFFFFFF)] This parameter is a bit-wise representation of the 24 CAMAC slots which may raise the LAM. It defines which CAMAC slot is allowed to trigger the call to the readout routine. (See read_trigger_event() ).
- ["MIDAS"] This line specifies the data format used for generating the event. The following options are possible: MIDAS, YBOS and FIXED. The format has to agree with the way the event is composed in the user read-out routine. It tells the system how to interpret an event when it is copied to the ODB or displayed in a user-readable form.
MIDAS and YBOS or FIXED and YBOS data format can be mixed at the frontend level, but the data logger (mlogger) is not able to handle this format diversity on a event-by-event basis. In practice a given experiment should keep the data format identical throughout the equipment definition.
- [TRUE] "enable" switch for the equipment. Only when enable (TRUE) the related equipment is active.
- [ RO_RUNNING] Specify when the read-out of an event should be occurring (transition state) or be enabled (state). Following options are possible:
RO_RUNNING | Read on state "running" |
RO_STOPPED | Read on state "stopped" |
RO_PAUSED | Read on state "paused" |
RO_BOR | Read after begin-of-run |
RO_EOR | Read before end-of-run |
RO_PAUSE | Read when run gets paused |
RO_RESUME | Read when run gets resumed |
RO_TRANSITIONS | Read on all transitions |
RO_ALWAYS | Read independently of the states and force a read for all transitions. |
RO_ODB | Equipment event mirrored into ODB under variables |
These flags can be combined with the logical OR operator. Trigger events in the above example are read out only when running while scaler events is read out when running and additionally on all transitions. A special flag RO_ODB tells the system to copy the event to the /Equipment/<equipment name>/Variables ODB tree once every ten seconds for diagnostic. Later on, the event content can then be displayed with ODBEdit.
- [500] Time interval for Periodic equipment (EQ_PERIODIC) or time out value in case of EQ_POLLING (unit in millisecond).
- [0 (stop after...)] Specify the number of events to be taken prior to forcing an End-Of-Run transition. The value 0 disables this option.
- [0 (Super Event )] Enable the Super event capability. Specify the maximum number of events in the Super event.
- [0 (History system )] Enable the MIDAS history system for that equipment. The value (positive in seconds) indicates the time interval for generating the event to be available for history logging by the mlogger task if running.
- ["","",""] Reserved field for system. Should be present and remain empty.
- [read_trigger_event()] User read-out routine declaration (could be any name). Every time the frontend is initialized, it copies the equipment settings to the ODB under /Equipment/<equipment name>/Common. A hot-link to that ODB tree is created allowing some of the settings to be changed during run-time. Modification of "Enabled" flag, RO_xxx flags, "period" and "event limit" from the ODB is immediately reflected into the frontend which will act upon them. This function has to be present in the frontend code and will be called for every trigger under one of the two conditions:
- [In polling mode] The poll_event has detected a trigger request while polling on a trigger source.
- [In interrupt mode] An interrupt source pre-defined through the interrupt_configuration has occurred.
- [Remark 1 ] The first argument of the readout function provides the pointer to the newly constructed event and points to the first valid location for storing the data.
- [Remark 2 ] The content of the memory location pointed by pevent prior to its uses in the readout function contains the LAM source bitwise register. This feature can be exploited in order to identify which slot has triggered the readout when multiple LAM has been assigned to the same readout function. Example:
... in the equipment declaration
...
LAM_SOURCE(JW_C, LAM_STATION(GE_N) | LAM_STATION(JW_N)),
...
"", "", "",
event_dispatcher,
...
INT event_dispatcher(char *pevent)
{
DWORD lam, dword;
INT size=0;
EQUIPMENT *eq;
lam = *((DWORD *)pevent);
if (lam & LAM_STATION(JW_N))
{
...
size = read_mcs_event(pevent);
...
else if (lam & LAM_STATION(GE_N))
{
...
size = read_ge_event(pevent);
...
return size;
- [Remark 3 ] In the example above, the Midas Event Header contains the same Event ID as the Trigger mask for both LAM. The event serial number will be incremented by one for every call to event_dispatcher() as long as the returned size is non-zero.
- [Remark 4 ] The return value should represent the number of bytes collected in this function. If the returned value is set to zero, The event will be dismissed and the serial number to that event will be decremented by one.
The FIXED format is the simplest event format. The event length is fixed and is mapped to a C structure that is filled by the readout routine. Since the standard MIDAS analyzer cannot work with this format, it is only recommended for experiment, which uses its own analyzer and wants to avoid the overhead of a bank structure. For fixed events, the structure has to be defined twice: Once for the compiler in form of a C structure and once for the ODB in form of an ASCII representation. The ASCII string is supplied to the system as the "init string" in the equipment list.
Following statements would define a fixed event with two ADC and TDC values:
typedef struct {
int adc0;
int adc1;
int tdc0;
int tdc1;
TRIGGER_EVENT;
char *trigger_event_str[] = {
"adc0 = INT : 0",
"adc1 = INT : 0",
"tdc0 = INT : 0",
"tdc1 = INT : 0",
ASUM_BANK;
The trigger_event_str has to be defined before the equipment list and a reference to it has to be placed in the equipment list like:
{
...
read_trigger_event,
poll_trigger_event,
trigger_event_str,
,
The readout routine could then look like this, where the <...> statements have to be filled with the appropriate code accessing the hardware:
INT read_trigger_event(char *pevent)
{
TRIGGER_EVENT *ptrg;
ptrg = (TRIGGER_EVENT *) pevent;
ptrg->adc0 = <...>;
ptrg->adc1 = <...>;
ptrg->tdc0 = <...>;
ptrg->tdc1 = <...>;
return sizeof(TRIGGER_EVENT);
The MIDAS event format is a variable length event format. It uses "banks" as subsets of an event. A bank is composed of a bank header followed by the data. The bank header itself is made of 3 fields i.e: bank name (4 char max), bank type, bank length. Usually a bank contains an array of values that logically belong together. For example, an experiment can generate an ADC bank, a TDC bank and a bank with trigger information. The length of a bank can vary from one event to another due to zero suppression from the hardware. Besides the variable data length support of the bank structure, another main advantage is the possibility for the analyzer to add more (calculated) banks during the analysis process to the event in process. After the first analysis stage, the event can contain additionally to the raw ADC bank a bank with calibrated ADC values called CADC bank for example. In this CADC bank the raw ADC values could be offset or gain corrected.
MIDAS banks are created in the frontend readout code with calls to the MIDAS library. Following routines exist:
- bk_init() , bk_init32() Initializes a bank structure in an event.
- bk_create() Creates a bank with a given name (exactly four characters)
- bk_close() Closes a bank previously opened with bk_create().
- bk_locate() Locates a bank within an event by its name.
- bk_iterate() Returns bank and data pointers to each bank in the event.
- bk_list() Constructs a string with all the banks' names in the event.
- bk_size() Returns the size in bytes of all banks including the bank headers in an event. The following code composes a event containing two ADC and two TDC values, the <...> statements have to be filled with specific code accessing the hardware:
Upon normal completion, the readout routine returns the event size in bytes. If the event is not valid, the routine can return zero. In this case no event is sent to the back-end. This can be used to implement a software event filter (sometimes called "third level trigger").
INT read_trigger_event(char *pevent)
{
WORD *pdata, a;
bk_init(pevent);
bk_create(pevent, "ADC0", TID_WORD, &pdata);
for (a=0 ; a<8 ; a++)
cami(1, 1, a, 0, pdata++);
bk_close(pevent, pdata);
bk_create(pevent, "TDC0", TID_WORD, &pdata);
for (a=0 ; a<8 ; a++)
cami(1, 2, a, 0, pdata++);
bk_close(pevent, pdata);
return bk_size(pevent);
The YBOS event format is also a bank format used in other DAQ systems. The advantage of using this format is the fact that recorded data can be analyzed with pre-existing analyzers understanding YBOS format. The disadvantage is that it has a slightly larger overhead than the MIDAS format and it supports fewer bank types. An introduction to YBOS can be found under:
YBOS
The scheme of bank creation is exactly the same as for MIDAS events, only the routines are named differently. The YBOS format is double word oriented i.e. all incrementation are done in 4 bytes steps. Following routines exist:
The following code creates an ADC0 bank in YBOS format:
INT read_trigger_event(char *pevent)
{
DWORD i;
DWORD *pbkdat;
ybk_init((DWORD *) pevent);
ybk_create((DWORD *)pevent, "ADC0", I4_BKTYPE, (DWORD *)(&pbkdat));
for (i=0 ; i<8 ; i++)
*pbkdat++ = i & 0xFFF;
ybk_close((DWORD *)pevent, pbkdat);
ybk_create((DWORD *)pevent, "TDC0", I2_BKTYPE, (DWORD *)(&pbkdat));
for (i=0 ; i<8 ; i++)
*((WORD *)pbkdat)++ = (WORD)(0x10+i) & 0xFFF;
ybk_close((DWORD *) pevent, pbkdat);
ybk_create((DWORD *)pevent, "SIMU", I2_BKTYPE, (DWORD *)(&pbkdat));
for (i=0 ; i<9 ; i++)
*((WORD *)pbkdat)++ = (WORD) (0x20+i) & 0xFFF;
ybk_close((DWORD *) pevent, I2_BKTYPE, pbkdat);
return (ybk_size((DWORD *)pevent));
This option permits the user to postpone any transition issued by any requester until some condition are satisfied. As examples:
- It may not be advised to pause or stop a run until let say some hardware has turned off a particular valve.
- The start of the acquisition system is postponed until the beam rate has been stable for a given period of time.
- While active, a particular acquisition system should not be interrupted until the "cycle" is complete.
In these examples, any application having access to the state of the hardware can register to be a "transition Deferred" client. It will then catch any transition request and postpone the trigger of such transition until condition is satisfied. The Deferred_Transition requires 3 steps for setup:
- Register the deferred transition.
- Provide callback function to serve the deferred transition
BOOL wait_end_cycle(int transition, BOOL first)
{
if (first)
{
transition_PS_requested = TRUE;
return FALSE;
if (end_of_mcs_cycle)
{
transition_PS_requested = FALSE;
end_of_mcs_cycle = FALSE;
return TRUE;
else
return FALSE;
...
- Implement the condition code
... In this case at the end of the readout function...
...
INT read_mcs_event(char *pevent, INT offset)
{
...
if (transition_PS_requested)
{
cam_lam_disable(JW_C,JW_N);
cam_lam_disable(GE_C,GE_N);
cam_lam_clear(JW_C,JW_N);
cam_lam_clear(GE_C,GE_N);
camc(GE_C,GE_N,0,GE_DISABLE);
end_of_mcs_cycle = TRUE;
re_arm_cycle();
return bk_size(pevent);
In the example above the frontend code register for PAUSE and STOP. The second argument of the cm_register wait_end_cycle is the declaration of the callback function. The callback function will be called as soon as the transition is requested and will provide the Boolean flag first to be TRUE. By setting the transition_PS_requested , the user will have the acknowledgment of the transition request. By returning FALSE from the callback you will prevent the transition to occur. As soon as the user condition is satisfied (end_of_mcs_cycle = TRUE), the return code in the callback will be set to TRUE and the requested transition will be issued. The Deferred transition shows up in the ODB under /runinfo/Requested transition and will contain the transition code (see State Codes & Transition Codes ). When the system is in deferred state, an ODBedit override command can be issued to force the transition to happen. eg: odbedit> stop now, odbedit> start now . This overide will do the transition function regarless of the state of the hardware involved.
The Super Event is an option implemented in the frontend code in order to reduce the amount of data to be transfered to the backend by removing the bank header for each event constructed. In other words, when an equipment readout in either MIDAS or YBOS format (bank format) is complete, the event is composed of the bank header followed by the data section. The overhead in bytes of the bank structure is 16 bytes for bk_init(), 20 bytes for bk_init32() and ybk_init(). If the data section size is close to the number above, the data transfer as well as the data storage has an non-negligible overhead. To address this problem, the equipment can be setup to generate a so called Super Event which is an event composed of the initial standard bank header for the first event of the super event and up to number of sub event maximum successive data section before the closing of the bank.
To demonstrate the use of it, let's see the following example:
- Define equipment to be able to generate Super Event
{ "GE",
2, 0x0002,
"SYSTEM",
#ifdef USE_INT
EQ_INTERRUPT,
#else
EQ_POLLED,
#endif
LAM_SOURCE(GE_C, LAM_STATION(GE_N)),
"MIDAS",
TRUE,
RO_RUNNING,
200,
0,
1000,
0,
"", "", "",
read_ge_event,
,
...
- Setup the readout function for Super Event collection.
#define NWORDS 3
INT read_ge_event(char *pevent, INT offset)
{
static WORD *pdata;
if (offset == 0)
{
bk_init(pevent);
bk_create(pevent, "GERM", TID_WORD, &pdata);
else if (offset == -1)
{
bk_close(pevent, pdata);
return bk_size(pevent);
cam16i(GE_C, GE_N, 0, GE_READ, pdata++);
cam16i(GE_C, GE_N, 1, GE_READ, pdata++);
cam16i(GE_C, GE_N, 2, GE_READ, pdata++);
re_arm_ge();
if (offset == 0)
{
return NWORDS * sizeof(WORD) + sizeof(BANK_HEADER) + sizeof(BANK);
else
return NWORDS * sizeof(WORD);
The encoded description of the data section is left to the user. If the number of words per sub-event is fixed (NWORD), the sub-event extraction is simple. In the case of variable sub-event length, it is necessary to tag the first or the last word of each sub-event. The content of the sub-event is essentially the responsibility of the user.
- [Remark 1 ] The backend analyzer will have to be informed by the user on the content structure of the data section of the event as no particular tagging is applied to the Super Event by the Midas transfer mechanism.
- [Remark 2 ] If the Super Event is composed in a remote equipment running a different Endian mode than the backend processor, it would be necessary to insure the data type consistency throughout the Super Event in order to guarantee the proper byte swapping of the data content.
- [Remark 3 ] The event rate in the equipment statistic will indicates the rate of sub-events.
Instead of talking directly to each other, frontend and control programs exchange information through the ODB. Each slow control equipment gets a corresponding ODB tree under /Equipment. This tree contains variables needed to control the equipment as well as variables measured by the equipment. In case of a high voltage equipment this is a Demand array which contains voltages to be set, a Measured array which contains read back voltages and a Current array which contains the current drawn from each channel. To change the voltage of a channel, a control program writes to the Demand array the desired value. This array is connected to the high voltage frontend via a ODB hot-link. Each time it gets modified, the frontend receives a notification and sets the new value. In the other direction the frontend continuously reads the voltage and current values from all channels and updates the according ODB arrays if there has been a significant change. This design has a possible inconvenience due to the fact that ODB is the key element of that control. Any failure or corruption of the database can result in wrong driver control. Therefore it is not recommended to use this system to control systems that need redundancy for safety purposes. On the other hand this system has several advantages:
- The control program does not need any knowledge of the frontend, it only talks to the ODB.
- The control variables only exist at one place that guarantees consistency among all clients.
- Basic control can be done through ODBEdit without the need of a special control program.
- A special control program can be tested without having a frontend running.
- In case of n frontend and m control programs, only n+m network connections are needed instead of n*m connection for point-to-point connections. Since all slow control values are contained in the ODB, they get automatically dumped to the logging channels. The slow control frontend uses the same framework as the normal frontend and behaves similar in many respects. They also create periodic events that contain the slow control variables and are logged together with trigger and scaler events. The only difference is that a routine is called periodically from the framework that has the task to read channels and to update the ODB. To access slow control hardware, a two-layer driver concept is used. The upper layer is a "class driver", which establishes the connection to the ODB variables and contains high level functionality like channel limits, ramping etc. It uses a "device driver" to access the channels. These drivers implement only very simple commands like "set channel" and "read channel". The device drivers themselves can use bus drivers like RS232 or GPIB to control the actual device.
Class driver, Device and Bus driver in the slow control system
The separation into class and device drivers has the advantage that it is very easy to add new devices, because only the simple device driver needs to be written. All higher functionality is inherited from the class driver. The device driver can implement richer functionality, depending on the hardware. For some high voltage devices there is a current read-back for example. This is usually reflected by additional variables in the ODB, i.e. a Current array. Frontend equipment uses exactly one class driver, but a class driver can use more than one device driver. This makes it possible to control several high voltage devices for example with one frontend in one equipment. The number of channels for each device driver is defined in the slow control frontend. Several equipment with different class drivers can be defined in a single frontend.
Key name Type #Val Size Last Opn Mode Value
---------------------------------------------------------------------------
Epics DIR
Settings DIR
Channels DIR
Epics INT 1 4 25h 0 RWD 3
Devices DIR
Epics DIR
Channel name STRING 10 32 25h 0 RWD
[0] GPS:VAR1
[1] GPS:VAR2
[2] GPS:VAR3
Names STRING 10 32 17h 1 RWD
[0] Current
[1] Voltage
[2] Watchdog
Update Threshold MeasureFLOAT 10 4 17h 0 RWD
[0] 2
[1] 2
[2] 2
Common DIR
Event ID WORD 1 2 17h 0 RWD 3
Trigger mask WORD 1 2 17h 0 RWD 0
Buffer STRING 1 32 17h 0 RWD SYSTEM
Type INT 1 4 17h 0 RWD 4
Source INT 1 4 17h 0 RWD 0
Format STRING 1 8 17h 0 RWD FIXED
Enabled BOOL 1 4 17h 0 RWD y
Read on INT 1 4 17h 0 RWD 121
Period INT 1 4 17h 0 RWD 60000
Event limit DOUBLE 1 8 17h 0 RWD 0
Num subevents DWORD 1 4 17h 0 RWD 0
Log history INT 1 4 17h 0 RWD 1
Frontend host STRING 1 32 17h 0 RWD hostname
Frontend name STRING 1 32 17h 0 RWD Epics
Frontend file name STRING 1 256 17h 0 RWD feepic.c
Variables DIR
Demand FLOAT 10 4 0s 1 RWD
[0] 1.56
[1] 120
[2] 87
Measured FLOAT 10 4 2s 0 RWD
[0] 1.56
[1] 120
[2] 87
Statistics DIR
Events sent DOUBLE 1 8 17h 0 RWDE 26
Events per sec. DOUBLE 1 8 17h 0 RWDE 0
kBytes per sec. DOUBLE 1 8 17h 0 RWDE 0
The Electronic logbook is an alternative way of recording experiment information. This is implemented through the Midas web server mhttpd task (see Elog page). The definition of the options can be found in the ODB data base under ODB /Elog Tree.
Midas provides a general log file midas.log for recording system and user messages across the different components of the data acquisition clients. The location of this file is dependent on the mode of installation of the system.
- [without ODB /Logger Tree] In this case the location is defined by either the MIDAS_DIR environment (see Environment variables ) or the definition of the experiment in the exptab file (see Experiment_Definition ). In both cases the log file will be in the experiment specific directory.
- [with /Logger Tree] The midas.log will be sitting into the defined directory specified by Data Dir .
midas.log file contains system and user messages generated by any application connected to the given experiment.
The MIDAS Macros definition provides a list of possible type of messages.
Fri Mar 24 10:48:40 2000 [CHAOS] Run 8362 started
Fri Mar 24 10:48:40 2000 [Logger] Run #8362 started
Fri Mar 24 10:55:04 2000 [Lazy_Tape] cni-043[10] (cp:383.6s) /dev/nst0/run08360.ybs 849.896MB file NEW
Fri Mar 24 11:24:03 2000 [MStatus] Program MStatus on host umelba started
Fri Mar 24 11:24:03 2000 [MStatus] Program MStatus on host umelba stopped
Fri Mar 24 11:27:02 2000 [Logger] stopping run after having received 1200000 events
Fri Mar 24 11:27:03 2000 [CHAOS] Run 8362 stopped
Fri Mar 24 11:27:03 2000 [SUSIYBOS] saving info in run log
Fri Mar 24 11:27:03 2000 [Logger] Run #8362 stopped
Fri Mar 24 11:27:13 2000 [Logger] starting new run
Fri Mar 24 11:27:14 2000 [CHAOS] Run 8363 started
Fri Mar 24 11:27:14 2000 [CHAOS] odb_access_file -I- /Equipment/kos_trigger/Dump not found
Fri Mar 24 11:27:14 2000 [Logger] Run #8363 started
Fri Mar 24 11:33:47 2000 [Lazy_Tape] cni-043[11] (cp:391.8s) /dev/nst0/run08361.ybs 850.209MB file NEW
Fri Mar 24 11:42:35 2000 [CHAOS] Run 8363 stopped
Fri Mar 24 11:42:40 2000 [SUSIYBOS] saving info in run log
Fri Mar 24 11:42:41 2000 [ODBEdit] Run #8363 stopped
Fri Mar 24 12:19:57 2000 [MChart] client [umelba.Triumf.CA]MChart failed watchdog test after 10 sec
Fri Mar 24 12:19:57 2000 [MChart] Program MChart on host koslx0 stopped
Quick Start - Top - Utilities
Midas DOC Version 2.0.1 ---- PSI Stefan Ritt ----
Contributions: Pierre-Andre Amaudruz - Sergio Ballestrero - Suzannah Daviel -
Doxygen - Peter Green -
Qing Gu - Greg Hackman - Gertjan Hofman - Paul Knowles - Exaos Lee - Rudi Meier - Glenn
Moloney - Dave Morris - John M O'Donnell - Konstantin Olchanski - Renee Poutissou
- Tamsen Schurman - Andreas Suter - Jan M.Wouters - Piotr Adam Zolnierczuk