ID |
Date |
Author |
Topic |
Subject |
2046
|
01 Dec 2020 |
Stefan Ritt | Forum | subrun | There is no "mechanism" foreseen to be executed after each subrun. But you could
run a shell script after each run which loops over all subruns and converts them
one after the other.
Stefan
> Hi,
>
> I was wondering if there is a "mechanism" to run an executable
> file after each subrun is closed...
>
> I need to convert .mid.lz4 subrun files to ROOT (TTree) files;
>
> Thanks,
> Gennaro |
2050
|
09 Dec 2020 |
Stefan Ritt | Forum | history and variables confusion | First, the writing of banks is completely independent of the history system. Banks go to the log file only,
while the history is only linked to the "Variables" section in the ODB.
Second, it's advisable to group similar equipment into one. Like if you have five power supplies powering
and experiment, you don't want to have five equipments Supply1, Supply2, ..., but only one equipment
"Power Supplies". In the frontend belonging to that equipment, you define a DEVICE_DRIVER list with
one entry for each power supply. If you interact with an mscb device, there are some helper functions
which simplify the definition of the equipment and which I can send you privately. So your device
driver looks a bit like the one attached.
If you cannot do that and absolutely want separate equipments, please post a complete ODB subtree of your
settings, and I can try to reproduce your problem.
Stefan
======================
DEVICE_DRIVER power_driver[] = {
{"Power Supply 1", mscbdev, 0, NULL, DF_INPUT | DF_MULTITHREAD},
{"Power Supply 2", mscbdev, 0, NULL, DF_INPUT | DF_MULTITHREAD},
{"Power Supply 3", mscbdev, 0, NULL, DF_INPUT | DF_MULTITHREAD},
{""}
};
...
INT frontend_init()
{
mscb_define("mscbxxx.psi.ch", "Power Supplies", "Power Supply 1", power_driver, 1, 0, "Output 1", 0.1);
mscb_define("mscbxxx.psi.ch", "Power Supplies", "Power Supply 1", power_driver, 1, 1, "Output 2", 0.1);
...
}
/*-- Function to define MSCB variables in a convenient way ---------*/
void mscb_define(const char *submaster, const char *equipment, const char *devname,
DEVICE_DRIVER *driver, int address, unsigned char var_index,
const char *name, double threshold)
{
int i, dev_index, chn_index, chn_total;
char str[256];
float f_threshold;
HNDLE hDB;
cm_get_experiment_database(&hDB, NULL);
if (submaster && submaster[0]) {
sprintf(str, "/Equipment/%s/Settings/Devices/%s/Device", equipment, devname);
db_set_value(hDB, 0, str, submaster, 32, 1, TID_STRING);
sprintf(str, "/Equipment/%s/Settings/Devices/%s/Pwd", equipment, devname);
db_set_value(hDB, 0, str, "meg", 32, 1, TID_STRING);
}
/* find device in device driver */
for (dev_index=0 ; driver[dev_index].name[0] ; dev_index++)
if (equal_ustring(driver[dev_index].name, devname))
break;
if (!driver[dev_index].name[0]) {
cm_msg(MERROR, "mscb_define", "Device \"%s\" not present in device driver list", devname);
return;
}
/* count total number of channels */
for (i=chn_total=0 ; i<=dev_index ; i++)
if (((driver[dev_index].flags & DF_INPUT) > 0 && (driver[i].flags & DF_INPUT)) ||
((driver[dev_index].flags & DF_OUTPUT) > 0 && (driver[i].flags & DF_OUTPUT)))
chn_total += driver[i].channels;
chn_index = driver[dev_index].channels;
sprintf(str, "/Equipment/%s/Settings/Devices/%s/MSCB Address", equipment, devname);
db_set_value_index(hDB, 0, str, &address, sizeof(int), chn_index, TID_INT, TRUE);
sprintf(str, "/Equipment/%s/Settings/Devices/%s/MSCB Index", equipment, devname);
db_set_value_index(hDB, 0, str, &var_index, sizeof(char), chn_index, TID_BYTE, TRUE);
if (threshold != -1 && (driver[dev_index].flags & DF_INPUT) > 0) {
sprintf(str, "/Equipment/%s/Settings/Update Threshold", equipment);
f_threshold = (float) threshold;
db_set_value_index(hDB, 0, str, &f_threshold, sizeof(float), chn_total, TID_FLOAT, TRUE);
}
if (name && name[0]) {
sprintf(str, "/Equipment/%s/Settings/Names %s", equipment, devname);
db_set_value_index(hDB, 0, str, name, 32, chn_total, TID_STRING, TRUE);
}
/* increment number of channels for this driver */
driver[dev_index].channels++;
} |
2059
|
16 Dec 2020 |
Stefan Ritt | Forum | Issues building banks. | > This is very hard to do using the mfe.c frontend. (the main reason I wrote the TMFE C++ frontend class).
Actually that's not true. Just look at
midas/examples/mtfe/mtfe.c
this is an example for a frontend with equipment with the EQ_USER flag, which allows you easily to run a separate
thread (or more) for event collection and processing. Of course all old-fashioned C style (code is from 2007) but it
works.
Stefan |
2062
|
18 Dec 2020 |
Stefan Ritt | Suggestion | Code formatting | May I ask for your quick opinion on code formatting. MIDAS had a coding style
which pretty much followed the ROOT coding style described at
https://root.cern/contribute/coding_conventions/
so we followed the "3 spaces indent" convention, braces according to Kernigham &
Ritchie and a few other things. I see however that code written by different
people still is formatted differently, like spaces before and after comparators
etc. I wonder if it would make sense to keep a consistent code formatting through
the whole midas repository.
Looking again at what the ROOT guys doe (see link above), they have a ClangFormat
file, which I attached to this post. Putting this file into the root of midas
ensures that all files are formatted in exactly the same way, which would increase
readability largely.
The nice thing with ClangFormat is that can be integrated into my editor (Clion) as
well as in emacs and vim:
https://clang.llvm.org/docs/ClangFormat.html
This would also make the emacs settings in our files obsolete:
/* emacs
* Local Variables:
* tab-width: 8
* c-basic-offset: 3
* indent-tabs-mode: nil
* End:
*/
I don't like these because they are only for people using emacs. If everybody would
put statements into the files with their favourite editor, all our source files
would be cluttered quite a bit.
So the question is now how style to use? I attached different trials with a simple
file from the distribution, so you can see the differences. They use the style from
- LLVM
- ROOT
- GNU
- Google
I consciously skipped the "Microsoft" style ;-)
Which one should we settle on? Any opinion? If I don't hear anything, I will pick a
style at the end of this year 2020. I have a slight favour of the ROOT style, although
I don't like that the "case" is not indented there under the opening brace of the
switch statement which seems inconsistent to me. The only one doing that right is the
Google format, but that one has an indentation of 2 chars instead our usual 3 chars.
At the end of the day I think it's not so important on which style we agree, as long
as we DO have a common style for all midas files.
Best,
Stefan |
Attachment 1: .clang-format
|
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -3
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
# This would be nice to have but seems to also (mis)align function parameters
AlignConsecutiveDeclarations: true
AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
# This option is "deprecated and is retained for backwards compatibility."
# AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 3
ContinuationIndentWidth: 3
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IncludeCategories:
- Regex: '^("|<)T'
Priority: 4
- Regex: '^("|<)ROOT/'
Priority: 5
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 6
IndentCaseLabels: false
IndentWidth: 3
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 3
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60000
PointerAlignment: Right
ReflowComments: true
SortIncludes: false
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 3
UseTab: Never
...
|
Attachment 2: cnaf_callback_llvm.cxx
|
/********************************************************************\
Name: cnaf_callback.c
Created by: Stefan Ritt
Created by: moved here from mfe.c by Konstantin Olchanski
Contents: The system part of the MIDAS frontend. Has to be
linked with user code to form a complete frontend
$Id$
\********************************************************************/
#include <stdio.h>
#include <assert.h>
#include "midas.h"
#include "msystem.h"
#include "mcstd.h"
/*------------------------------------------------------------------*/
static int cnaf_debug = 0;
INT cnaf_callback(INT index, void *prpc_param[]) {
DWORD cmd, b, c, n, a, f, *pdword, *size, *x, *q, dtemp;
WORD *pword, *pdata, temp;
INT i, count;
/* Decode parameters */
cmd = CDWORD(0);
b = CDWORD(1);
c = CDWORD(2);
n = CDWORD(3);
a = CDWORD(4);
f = CDWORD(5);
pdword = CPDWORD(6);
pword = CPWORD(6);
pdata = CPWORD(6);
size = CPDWORD(7);
x = CPDWORD(8);
q = CPDWORD(9);
/* determine repeat count */
if (index == RPC_CNAF16)
count = *size / sizeof(WORD); /* 16 bit */
else
count = *size / sizeof(DWORD); /* 24 bit */
switch (cmd) {
/*---- special commands ----*/
case CNAF_INHIBIT_SET: cam_inhibit_set(c);
break;
case CNAF_INHIBIT_CLEAR: cam_inhibit_clear(c);
break;
case CNAF_CRATE_CLEAR: cam_crate_clear(c);
break;
case CNAF_CRATE_ZINIT: cam_crate_zinit(c);
break;
case CNAF_TEST: break;
case CNAF:
if (index == RPC_CNAF16) {
for (i = 0; i < count; i++)
if (f < 16)
cam16i_q(c, n, a, f, pword++, (int *) x, (int *) q);
else if (f < 24)
cam16o_q(c, n, a, f, pword[i], (int *) x, (int *) q);
else
cam16i_q(c, n, a, f, &temp, (int *) x, (int *) q);
} else {
for (i = 0; i < count; i++)
if (f < 16)
cam24i_q(c, n, a, f, pdword++, (int *) x, (int *) q);
else if (f < 24)
cam24o_q(c, n, a, f, pdword[i], (int *) x, (int *) q);
else
cam24i_q(c, n, a, f, &dtemp, (int *) x, (int *) q);
}
break;
case CNAF_nQ:
if (index == RPC_CNAF16) {
if (f < 16) {
cam16i_rq(c, n, a, f, &pword, count);
*size = (POINTER_T) pword - (POINTER_T) pdata;
}
} else {
if (f < 16) {
cam24i_rq(c, n, a, f, &pdword, count);
*size = (POINTER_T) pdword - (POINTER_T) pdata;
}
}
/* return reduced return size */
break;
default: printf("cnaf: Unknown command 0x%X\n", (unsigned int) cmd);
}
if (cnaf_debug) {
if (index == RPC_CNAF16)
printf("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n", (int) cmd, (int) count, (int) c, (int) n, (int) a,
(int) f, (int) pword[0], (int) *x, (int) *q);
else if (index == RPC_CNAF24)
printf("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n", (int) cmd, (int) count, (int) c, (int) n, (int) a,
(int) f, (int) pdword[0], (int) *x, (int) *q);
}
return RPC_SUCCESS;
}
void register_cnaf_callback(int debug) {
cnaf_debug = debug;
/* register CNAF callback */
cm_register_function(RPC_CNAF16, cnaf_callback);
cm_register_function(RPC_CNAF24, cnaf_callback);
}
/* end file */
|
Attachment 3: cnaf_callback_root.cxx
|
/********************************************************************\
Name: cnaf_callback.c
Created by: Stefan Ritt
Created by: moved here from mfe.c by Konstantin Olchanski
Contents: The system part of the MIDAS frontend. Has to be
linked with user code to form a complete frontend
$Id$
\********************************************************************/
#include <stdio.h>
#include <assert.h>
#include "midas.h"
#include "msystem.h"
#include "mcstd.h"
/*------------------------------------------------------------------*/
static int cnaf_debug = 0;
INT cnaf_callback(INT index, void *prpc_param[])
{
DWORD cmd, b, c, n, a, f, *pdword, *size, *x, *q, dtemp;
WORD *pword, *pdata, temp;
INT i, count;
/* Decode parameters */
cmd = CDWORD(0);
b = CDWORD(1);
c = CDWORD(2);
n = CDWORD(3);
a = CDWORD(4);
f = CDWORD(5);
pdword = CPDWORD(6);
pword = CPWORD(6);
pdata = CPWORD(6);
size = CPDWORD(7);
x = CPDWORD(8);
q = CPDWORD(9);
/* determine repeat count */
if (index == RPC_CNAF16)
count = *size / sizeof(WORD); /* 16 bit */
else
count = *size / sizeof(DWORD); /* 24 bit */
switch (cmd) {
/*---- special commands ----*/
case CNAF_INHIBIT_SET: cam_inhibit_set(c); break;
case CNAF_INHIBIT_CLEAR: cam_inhibit_clear(c); break;
case CNAF_CRATE_CLEAR: cam_crate_clear(c); break;
case CNAF_CRATE_ZINIT: cam_crate_zinit(c); break;
case CNAF_TEST: break;
case CNAF:
if (index == RPC_CNAF16) {
for (i = 0; i < count; i++)
if (f < 16)
cam16i_q(c, n, a, f, pword++, (int *)x, (int *)q);
else if (f < 24)
cam16o_q(c, n, a, f, pword[i], (int *)x, (int *)q);
else
cam16i_q(c, n, a, f, &temp, (int *)x, (int *)q);
} else {
for (i = 0; i < count; i++)
if (f < 16)
cam24i_q(c, n, a, f, pdword++, (int *)x, (int *)q);
else if (f < 24)
cam24o_q(c, n, a, f, pdword[i], (int *)x, (int *)q);
else
cam24i_q(c, n, a, f, &dtemp, (int *)x, (int *)q);
}
break;
case CNAF_nQ:
if (index == RPC_CNAF16) {
if (f < 16) {
cam16i_rq(c, n, a, f, &pword, count);
*size = (POINTER_T)pword - (POINTER_T)pdata;
}
} else {
if (f < 16) {
cam24i_rq(c, n, a, f, &pdword, count);
*size = (POINTER_T)pdword - (POINTER_T)pdata;
}
}
/* return reduced return size */
break;
default: printf("cnaf: Unknown command 0x%X\n", (unsigned int)cmd);
}
if (cnaf_debug) {
if (index == RPC_CNAF16)
printf("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n", (int)cmd, (int)count, (int)c, (int)n, (int)a,
(int)f, (int)pword[0], (int)*x, (int)*q);
else if (index == RPC_CNAF24)
printf("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n", (int)cmd, (int)count, (int)c, (int)n, (int)a,
(int)f, (int)pdword[0], (int)*x, (int)*q);
}
return RPC_SUCCESS;
}
void register_cnaf_callback(int debug)
{
cnaf_debug = debug;
/* register CNAF callback */
cm_register_function(RPC_CNAF16, cnaf_callback);
cm_register_function(RPC_CNAF24, cnaf_callback);
}
/* end file */
|
Attachment 4: cnaf_callback_gnu.cxx
|
/********************************************************************\
Name: cnaf_callback.c
Created by: Stefan Ritt
Created by: moved here from mfe.c by Konstantin Olchanski
Contents: The system part of the MIDAS frontend. Has to be
linked with user code to form a complete frontend
$Id$
\********************************************************************/
#include <stdio.h>
#include <assert.h>
#include "midas.h"
#include "msystem.h"
#include "mcstd.h"
/*------------------------------------------------------------------*/
static int cnaf_debug = 0;
INT cnaf_callback (INT index, void *prpc_param[])
{
DWORD cmd, b, c, n, a, f, *pdword, *size, *x, *q, dtemp;
WORD *pword, *pdata, temp;
INT i, count;
/* Decode parameters */
cmd = CDWORD(0);
b = CDWORD(1);
c = CDWORD(2);
n = CDWORD(3);
a = CDWORD(4);
f = CDWORD(5);
pdword = CPDWORD(6);
pword = CPWORD(6);
pdata = CPWORD(6);
size = CPDWORD(7);
x = CPDWORD(8);
q = CPDWORD(9);
/* determine repeat count */
if (index == RPC_CNAF16)
count = *size / sizeof (WORD); /* 16 bit */
else
count = *size / sizeof (DWORD); /* 24 bit */
switch (cmd)
{
/*---- special commands ----*/
case CNAF_INHIBIT_SET: cam_inhibit_set (c);
break;
case CNAF_INHIBIT_CLEAR: cam_inhibit_clear (c);
break;
case CNAF_CRATE_CLEAR: cam_crate_clear (c);
break;
case CNAF_CRATE_ZINIT: cam_crate_zinit (c);
break;
case CNAF_TEST: break;
case CNAF:
if (index == RPC_CNAF16)
{
for (i = 0; i < count; i++)
if (f < 16)
cam16i_q (c, n, a, f, pword++, (int *) x, (int *) q);
else if (f < 24)
cam16o_q (c, n, a, f, pword[i], (int *) x, (int *) q);
else
cam16i_q (c, n, a, f, &temp, (int *) x, (int *) q);
}
else
{
for (i = 0; i < count; i++)
if (f < 16)
cam24i_q (c, n, a, f, pdword++, (int *) x, (int *) q);
else if (f < 24)
cam24o_q (c, n, a, f, pdword[i], (int *) x, (int *) q);
else
cam24i_q (c, n, a, f, &dtemp, (int *) x, (int *) q);
}
break;
case CNAF_nQ:
if (index == RPC_CNAF16)
{
if (f < 16)
{
cam16i_rq (c, n, a, f, &pword, count);
*size = (POINTER_T) pword - (POINTER_T) pdata;
}
}
else
{
if (f < 16)
{
cam24i_rq (c, n, a, f, &pdword, count);
*size = (POINTER_T) pdword - (POINTER_T) pdata;
}
}
/* return reduced return size */
break;
default: printf ("cnaf: Unknown command 0x%X\n", (unsigned int) cmd);
}
if (cnaf_debug)
{
if (index == RPC_CNAF16)
printf ("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n", (int) cmd, (int) count, (int) c, (int) n, (int) a,
(int) f, (int) pword[0], (int) *x, (int) *q);
else if (index == RPC_CNAF24)
printf ("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n", (int) cmd, (int) count, (int) c, (int) n, (int) a,
(int) f, (int) pdword[0], (int) *x, (int) *q);
}
return RPC_SUCCESS;
}
void register_cnaf_callback (int debug)
{
cnaf_debug = debug;
/* register CNAF callback */
cm_register_function (RPC_CNAF16, cnaf_callback);
cm_register_function (RPC_CNAF24, cnaf_callback);
}
/* end file */
|
Attachment 5: cnaf_callback_google.cxx
|
/********************************************************************\
Name: cnaf_callback.c
Created by: Stefan Ritt
Created by: moved here from mfe.c by Konstantin Olchanski
Contents: The system part of the MIDAS frontend. Has to be
linked with user code to form a complete frontend
$Id$
\********************************************************************/
#include <stdio.h>
#include <assert.h>
#include "midas.h"
#include "msystem.h"
#include "mcstd.h"
/*------------------------------------------------------------------*/
static int cnaf_debug = 0;
INT cnaf_callback(INT index, void *prpc_param[]) {
DWORD cmd, b, c, n, a, f, *pdword, *size, *x, *q, dtemp;
WORD *pword, *pdata, temp;
INT i, count;
/* Decode parameters */
cmd = CDWORD(0);
b = CDWORD(1);
c = CDWORD(2);
n = CDWORD(3);
a = CDWORD(4);
f = CDWORD(5);
pdword = CPDWORD(6);
pword = CPWORD(6);
pdata = CPWORD(6);
size = CPDWORD(7);
x = CPDWORD(8);
q = CPDWORD(9);
/* determine repeat count */
if (index == RPC_CNAF16)
count = *size / sizeof(WORD); /* 16 bit */
else
count = *size / sizeof(DWORD); /* 24 bit */
switch (cmd) {
/*---- special commands ----*/
case CNAF_INHIBIT_SET: cam_inhibit_set(c);
break;
case CNAF_INHIBIT_CLEAR: cam_inhibit_clear(c);
break;
case CNAF_CRATE_CLEAR: cam_crate_clear(c);
break;
case CNAF_CRATE_ZINIT: cam_crate_zinit(c);
break;
case CNAF_TEST: break;
case CNAF:
if (index == RPC_CNAF16) {
for (i = 0; i < count; i++)
if (f < 16)
cam16i_q(c, n, a, f, pword++, (int *) x, (int *) q);
else if (f < 24)
cam16o_q(c, n, a, f, pword[i], (int *) x, (int *) q);
else
cam16i_q(c, n, a, f, &temp, (int *) x, (int *) q);
} else {
for (i = 0; i < count; i++)
if (f < 16)
cam24i_q(c, n, a, f, pdword++, (int *) x, (int *) q);
else if (f < 24)
cam24o_q(c, n, a, f, pdword[i], (int *) x, (int *) q);
else
cam24i_q(c, n, a, f, &dtemp, (int *) x, (int *) q);
}
break;
case CNAF_nQ:
if (index == RPC_CNAF16) {
if (f < 16) {
cam16i_rq(c, n, a, f, &pword, count);
*size = (POINTER_T) pword - (POINTER_T) pdata;
}
} else {
if (f < 16) {
cam24i_rq(c, n, a, f, &pdword, count);
*size = (POINTER_T) pdword - (POINTER_T) pdata;
}
}
/* return reduced return size */
break;
default: printf("cnaf: Unknown command 0x%X\n", (unsigned int) cmd);
}
if (cnaf_debug) {
if (index == RPC_CNAF16)
printf("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n", (int) cmd, (int) count, (int) c, (int) n, (int) a,
(int) f, (int) pword[0], (int) *x, (int) *q);
else if (index == RPC_CNAF24)
printf("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n", (int) cmd, (int) count, (int) c, (int) n, (int) a,
(int) f, (int) pdword[0], (int) *x, (int) *q);
}
return RPC_SUCCESS;
}
void register_cnaf_callback(int debug) {
cnaf_debug = debug;
/* register CNAF callback */
cm_register_function(RPC_CNAF16, cnaf_callback);
cm_register_function(RPC_CNAF24, cnaf_callback);
}
/* end file */
|
2063
|
04 Jan 2021 |
Stefan Ritt | Suggestion | Code formatting | After pondering over the holidays, I decided to use the widely used LLVM code formatting,
just adapted slightly for 3 spaces and "case" indentation in a "switch" statement. This
formatting is now very close to our original one. Nevertheless, I did not reformat all
existing code, since that would screw up the git repository, and you cannot see then anymore
who wrote which line of code. But having the .clang-format file now in the midas root, all
NEW files fill follow that standard.
The CLion editor automatically picks up the .clang-format file if your enable ClangFomrat
via Preferences -> Code Style -> General -> Enable ClangFormat.
EMACS can also use this file by adding following lines to your .emacs:
(load "<path-to-clang>/tools/clang-format/clang-format.el")
(global-set-key [C-M-tab] 'clang-format-region)
One problem left is if you check out midas on a new machine, you might not have there your
personal .emacs file. If there is a way to ship a .emacs with midas, which gets
automatically loaded, I would be happy to put this into the distribution.
Stefan |
Attachment 1: .clang-format
|
# Generated from CLion C/C++ Code Style settings
BasedOnStyle: LLVM
AccessModifierOffset: -3
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignOperands: false
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: MultiLine
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
ColumnLimit: 0
CompactNamespaces: false
ContinuationIndentWidth: 3
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 3
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PointerAlignment: Right
ReflowComments: false
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 0
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 3
UseTab: Never
|
2066
|
06 Jan 2021 |
Stefan Ritt | Bug Report | Logger: Disk nearly full. | The logger simple requests the disk free space level from the operating system in the same
way as the "df" command does. Can you do a "df" on your system? I have seen that some file
systems free up space not immediately if you delete files, but some times later (like 24h).
Stefan |
2067
|
06 Jan 2021 |
Stefan Ritt | Suggestion | Improving variable functionality in Sequencer? | I guess you use a wrong pattern here. There is no need to copy ODB values to local variables,
then change them, then write them back. You can rather directly write values to the ODB. We run
all our experiments in that way and we can do what we want. So most of our scripts have sections
like
ODBSUBDIR "/Equipment/Laser/Variables"
ODBSET "Setting[*]", 0, 0
ODBSET "Output[1]", 0, 0
ODBSET "Output[2]", 1, 0
ODBSET "Output[3]", 0, 0
ODBSET "Output[4]", 1, 1
ENDODBSUBDIR
Note that both the path and the indices can contain wild cards, making this pattern more
flexible. Wildcards are however not (yet) supported for local variables, that's why we use
directly the ODBSET directive.
I attach a larger example from the MEG experiment here for your reference.
Stefan |
Attachment 1: laser.msl
|
COMMENT "TC laser run"
# include XEC setting script
INCLUDE xec_settings
RUNDESCRIPTION "TC laser run"
SET Nrun, 1
SET Freq, 1200
ODBSET "/Experiment/Run Parameters/SQL/SPX/SPXConfId", 79, 0
ODBGET "/Sequencer/Variables/Freq", Freq
ODBSET "/Sequencer/Variables/Freq", 1200, 1
SET Power, 12
SET Temp, 15
SET LaserFreq, 40
SET Nevent, 3000
ODBGET "/Sequencer/Variables/Nevent", Nevent
ODBSET "/Sequencer/Variables/Nevent", 3000, 1
SET Gain, 100
SET PzcLevel, 7
# Reset XEC setting
CALL setup_ADC, 0
CALL setup_DRS, 0
ODBSUBDIR "/Equipment/Trigger/Settings/WaveDAQ/"
ODBSET "AUXCrate/AUX-13/SamplingFrequency", $Freq, 0
ODBSET "AUXCrate/AUX-13/FrontendPzcLevel", 3, 0
ODBSET "AUXCrate/AUX-13/FrontendGain[14]", 1, 0
ODBSET "AUXCrate/AUX-13/FrontendPzc[14]", n, 0
ODBSET "AUXCrate/AUX-13/FrontendGain[15]", 1, 0
ODBSET "AUXCrate/AUX-13/FrontendPzc[15]", y, 0
ODBSET "AUXCrate/AUX-13/DRSChannelTxEnable", 0x3FFFFx,0
ODBSET "AUXCrate/AUX-13/ZeroSuppressionEnable", n, 0
ODBSET "TCUS1Crate/TU1-*/SamplingFrequency", $Freq, 0
ODBSET "TCUS1Crate/TU1-*/FrontendPzcLevel", $PzcLevel, 0
ODBSET "TCUS1Crate/TU1-*/FrontendPzc[*]", y, 0
ODBSET "TCUS1Crate/TU1-*/DRSChannelTxEnable", 0x3FFFF,0
ODBSET "TCUS1Crate/TU1-*/ZeroSuppressionEnable", n, 0
ODBSET "TCUS1Crate/TU1-*/FrontendGain[*]", $Gain, 0
ODBSET "TCUS1Crate/TU1-6/FrontendGain[*]", 50, 0
ODBSET "TCUS1Crate/TU1-*/TDCChannelTxEnable", 0,0
ENDODBSUBDIR
ODBSUBDIR "/Equipment/Trigger/Settings/WaveDAQ"
ODBSET "Trigger/MASTER/TriggerPrescaling[*]", 0, 0
ODBSET "Trigger/MASTER/TriggerEnable[*]", n, 0
ODBSET "Trigger/MASTER/TriggerPrescaling[63]", 1, 0
ODBSET "Trigger/MASTER/TriggerEnable[63]", y, 0
ODBSET "Trigger/MASTER/Write TRGC", y, 0
ODBSET "Trigger/MASTER/Write TGEN", y, 0
ODBSET "Trigger/MASTER/Write XEC", n, 0
ODBSet "Trigger/TC/Write SPX", n, 0
ENDODBSUBDIR
ODBSUBDIR ""
ENDODBSUBDIR
ODBSET "/Equipment/Trigger/Settings/Reload all", y, 1
WAIT ODBValue, "/Equipment/Trigger/Variables/Config busy", ==, 0
WAIT seconds, 2
ODBSUBDIR "/Equipment/Trigger/Settings/WaveDAQ"
ODBSET "Trigger/MASTER/TriggerPrescaling[*]", 0, 0
ODBSET "Trigger/MASTER/TriggerEnable[*]", n, 0
ODBSET "Trigger/MASTER/TriggerPrescaling[63]", 100, 0
ODBSET "Trigger/MASTER/TriggerEnable[63]", y, 1
ENDODBSUBDIR
ODBSUBDIR ""
ENDODBSUBDIR
CAT description, "TC pedestal"
ODBSET "/Experiment/Run Parameters/Run description", $description, 1
LOOP $Nrun
TRANSITION start
WAIT events, 1000
TRANSITION stop
ENDLOOP
ODBSUBDIR "/Equipment/Trigger/Settings/WaveDAQ"
ODBSET "Trigger/MASTER/TriggerPrescaling[*]", 0, 0
ODBSET "Trigger/MASTER/TriggerEnable[*]", n, 0
ODBSET "Trigger/MASTER/TriggerPrescaling[23]", 1, 0
ODBSET "Trigger/MASTER/TriggerEnable[23]", y, 1
ENDODBSUBDIR
ODBSUBDIR "/Equipment/Laser/Variables/"
ODBSET "Output[0]", $LaserFreq, 0
ODBSET "Output[1]", 1, 0
ODBSET "Output[2]", 1, 0
ODBSET "Output[3]", 1, 0
ODBSET "Output[4]", 0, 1
ENDODBSUBDIR
WAIT seconds, 10
ODBSUBDIR ""
ENDODBSUBDIR
CAT description, "Laser run, sector: 4, frequency: ", $Freq, ", clock: square, power: ", $Power, ", attenuator: 0, temperature: ", $Temp
ODBSET "/Experiment/Run Parameters/Run description", $description, 1
LOOP $Nrun
TRANSITION start
WAIT events, $Nevent
TRANSITION stop
ENDLOOP
ODBSUBDIR "/Equipment/Laser/Variables/"
ODBSET "Output[1]", 1, 0
ODBSET "Output[2]", 0, 0
ODBSET "Output[3]", 0, 0
ODBSET "Output[4]", 1, 1
ENDODBSUBDIR
WAIT seconds, 10
ODBSUBDIR ""
ENDODBSUBDIR
CAT description, "Laser run, sector: 5, frequency: ", $Freq, ", clock: square, power: ", $Power, ", attenuator: 0, temperature: ", $Temp
ODBSET "/Experiment/Run Parameters/Run description", $description, 1
LOOP $Nrun
TRANSITION start
WAIT events, $Nevent
TRANSITION stop
ENDLOOP
ODBSUBDIR "/Equipment/Laser/Variables"
ODBSET "Output[1]", 0, 0
ODBSET "Output[2]", 1, 0
ODBSET "Output[3]", 0, 0
ODBSET "Output[4]", 1, 1
ENDODBSUBDIR
WAIT seconds, 10
ODBSUBDIR ""
ENDODBSUBDIR
CAT description, "Laser run, sector: 6, frequency: ", $Freq, ", clock: square, power: ", $Power, ", attenuator: 0, temperature: ", $Temp
ODBSET "/Experiment/Run Parameters/Run description", $description, 1
LOOP $Nrun
TRANSITION start
WAIT events, $Nevent
TRANSITION stop
ENDLOOP
ODBSUBDIR "/Equipment/Laser/Variables"
ODBSET "Output[1]", 1, 0
ODBSET "Output[2]", 1, 0
ODBSET "Output[3]", 0, 0
ODBSET "Output[4]", 1, 1
ENDODBSUBDIR
WAIT seconds, 10
ODBSUBDIR ""
ENDODBSUBDIR
CAT description, "Laser run, sector: 7, frequency: ", $Freq, ", clock: square, power: ", $Power, ", attenuator: 0, temperature: ", $Temp
ODBSET "/Experiment/Run Parameters/Run description", $description, 1
LOOP $Nrun
TRANSITION start
WAIT events, $Nevent
TRANSITION stop
ENDLOOP
ODBSUBDIR "/Equipment/Laser/Variables"
ODBSET "Output[0]", 0, 0
ODBSET "Output[1]", 1, 0
ODBSET "Output[2]", 0, 0
ODBSET "Output[3]", 0, 0
ODBSET "Output[4]", 0, 1
ENDODBSUBDIR
ODBSUBDIR "/Equipment/Trigger/Settings/WaveDAQ"
ODBSET "AUXCrate/AUX-13/SamplingFrequency", 1200, 0
ODBSET "AUXCrate/AUX-13/FrontendPzcLevel", 7, 0
ODBSET "AUXCrate/AUX-13/FrontendGain[14]", 1, 0
ODBSET "AUXCrate/AUX-13/FrontendPzc[14]", n, 0
ODBSET "AUXCrate/AUX-13/FrontendGain[15]", 1, 0
ODBSET "AUXCrate/AUX-13/FrontendPzc[15]", n, 1
ENDODBSUBDIR
|
2070
|
08 Jan 2021 |
Stefan Ritt | Forum | history and variables confusion | We kind of agreed to rewrite the slow control system in C++. Each device will have its own driver derived from a common base class implementing the general communication. The reason we need a "system" and not only a "hand-written" driver is because we want:
- glue many device drivers together for a single equipment
- have a dedicated readout thread for every device, in order not to block other devices
- have a common error reporting scheme working with several threads
- being able to disable/enable individual devices without changing the history system each time
- having a common naming scheme for all devices (like "enforce" /Equipment/<name>/Settings/Names xxx) which is needed by the history system
- ...
Will see when we have time for that.
Stefan |
2074
|
13 Jan 2021 |
Stefan Ritt | Forum | poll_event() is very slow. | Something must be wrong on your side. If you take the example frontend under
midas/examples/experiment/frontend.cxx
and let it run to produce dummy events, you get about 90 Hz. This is because we have a
ss_sleep(10);
in the read_trigger_event() routine to throttle things down. If you remove that sleep,
you get an event rate of about 500'000 Hz. So the framework is really quick.
Probably your routine which looks for a 'lam' takes really long and should be fixed.
Stefan |
2080
|
25 Jan 2021 |
Stefan Ritt | Suggestion | mhttpd browser caching | Let me first explain a bit why caching is there. Once we had the case that someone from
TRIUMF opened a midas custom page at T2K. It took about one minute (!) to load the page.
When we looked at it, we found that the custom page pulled about 100 items with individual
HTTP requests from Japan, each taking about one second for the roundtrip. Then we redesigned
the custom page communication so that many ODB entries could be retrieved in one operation,
which improved the loading time from 100s to about 2s.
With the buttons we will have to make the same compromise. If we do not cache anything,
loading the midas status page over the Pacific takes many seconds. If we cache all, any
change on the midas side will not be reflected on the web page. So there is a compromise
to be made. I thought I designed it such that the side menu is cached locally, but when
the user presses "reload", then the full menu is fetched from the server. Of course one
has to remember this, so changing the ELOG URL or other things on the menu require a
reload (or wait a certain time for the cache to expire). So try again if that's working
for you. If not, I can visit it again and check if there is any bug.
If we go the route to disable the cache, better try this to T2K and see what you get before
we commit ourselves to that. Last time TRIUMF people were complaining a lot about long
load times.
Best,
Stefan |
2086
|
08 Feb 2021 |
Stefan Ritt | Suggestion | mhttpd browser caching | > It seems that the only reliable way to bypass the browser cache is to add
> a tag with a random number to the URL ("&ts=currenttime").
Indeed that's the only reliable way to avoid caching across browsers. An alternative is
("&r=" + Math.random())
to add a random number.
> BTW, things like midas.js are also cached, and it is common to see problems
> after updating midas, where status.html is newly loaded, but midas.js is an old
> stale version from cache.
Reloading JavaScript file NOT from the cache is really tricky these days. I added a
special Google Chrome extension to clear my browser cache, which works reliably:
https://chrome.google.com/webstore/detail/clear-cache/cppjkneekbjaeellbfkmgnhonkkjfpdn
Stefan |
2097
|
25 Feb 2021 |
Stefan Ritt | Bug Report | history reload | I have to reproduce the problem. Can you please send me the full link by direct email. As you know, I'm also at PSI.
Stefan |
2116
|
02 Mar 2021 |
Stefan Ritt | Info | shortest possible sleep | Why do you need that? Periodic equipment typically runs ever ten seconds or so, meaning one can do this easily in a scheduler.
For polled equipment, you don't want to sleep at all. Because if you sleep, you might miss an event. That's why I put my poll in mfe.c into a for() loop. No
sleep, maximum polling rate. I just double checked on my macbook air.
- If poll is always false (no event available), the loop executes 50M times in 100ms (calibrated during startup of the frontend). That means one iteration
takes 2ns (!). So if an event occurs, the readout is started with a 2ns overhead. No sleep can beat that. In a real world application, one has to add of course
the VME access or so to poll for the event.
- If poll is always true, the framework generates about 700k events each second (returning jus a few bytes of event data).
So if one adds any sleep here, things can get only worse, so I don't see the point for that. Of course polling eats one kernel at 100%, but these days every
CPU has more than one, even my 800 MHz Xilinx embedded ARM CPU (Zynq).
Best,
Stefan |
Draft
|
04 Mar 2021 |
Stefan Ritt | Forum | Using JSROOT.openFile with Midas | I also need midas events going back to the |
2122
|
04 Mar 2021 |
Stefan Ritt | Forum | Using JSROOT.openFile with Midas | I also need midas events going back to the browser for single event display, so put +1 for me.
Please also consider to use JavaScript typed arrays instead of JSON. For large midas banks, type
arrays are 5-10 times faster than JSON encoding/decoding.
Best,
Stefan |
2127
|
10 Mar 2021 |
Stefan Ritt | Forum | INT INT32 in experim.h | Ok, I added
/* define integer types with explicit widths */
#ifndef NO_INT_TYPES_DEFINE
typedef unsigned char UINT8;
typedef char INT8;
typedef unsigned short UINT16;
typedef short INT16;
typedef unsigned int UINT32;
typedef int INT32;
typedef unsigned long long UINT64;
typedef long long INT64;
#endif
to cover all new types. If there is a collision with user defined types, compile your program with -DNO_INT_TYPES_DEFINE and you remove the
above definition. I hope there are no other conflicts.
Stefan |
2129
|
10 Mar 2021 |
Stefan Ritt | Suggestion | embed modbvalue in SVG | You can't really embed it, but you can overlay it. You tag the SVG with a
"relative" position and then move the modbvalue with an "absolute" position over
it:
<svg style="position:relative" width="400" height="100">
<rect width="300" height="100" style="fill:rgb(255,0,0);stroke-width:3;stroke:rgb(0,0,0)" />
<div class="modbvalue" style="position:absolute;top:50px;left:50px" data-odb-path="/Runinfo/Run number"></div>
</svg> |
2135
|
24 Mar 2021 |
Stefan Ritt | Bug Report | Time shift in history CSV export | I confirm there is a problem. If variables are from the same equipment, they have the same
time stamps, like
t1 v1(t1) v2(t1)
t2 v1(t2) v2(t2)
t3 v1(t3) v2(t3)
when they are from different equipments, they have however different time stamps
t1 v1(t1)
t2 v2(t2)
t3 v1(t3)
t4 v2(t4)
The bug in the current code is that all variables use the time stamps of the first variable,
which is wrong in the case of different equipments, like
t1 v1(t1) v2(*t2*)
t3 v1(t3) v2(*t4*)
So I can change the code, but I'm not sure what would be the bast way. The easiest would be to
export one array per variable, like
t1 v1(t1)
t2 v1(t2)
...
t3 v2(t3)
t4 v2(t4)
...
Putting that into a single array would leave gaps, like
t1 v1(t1) [gap]
t2 [gap] v2(t2)
t3 v1(t3) [gap]
t4 [ga]] v2(t4)
plus this is programmatically more complicated, since I have to merge two arrays. So which
export format would you prefer?
Stefan |
2151
|
13 Apr 2021 |
Stefan Ritt | Forum | Client gets immediately removed when using a script button. | > I have followed your suggestions and the program still stops immediately. My status as returned from "cm_yield(100)" is always 412 (SS_TIMEOUT) which is fine.
> The issue is that, when run with the script button, the do-wile loop stops immediately because the !ss_kbhit() always evaluates to FALSE.
>
> My temporary solution has been to let the loop run forever :)
Ahh, could be that ss_kbhit() misbehaves if there is no keyboard, meaning that it is started in the background as a script.
We never had the issue before, since all "standard" midas programs like mlogger, mhttpd etc. also use ss_kbhit() and they
can be started in the background via the "-D" flag, but maybe the stdin is then handled differentlhy.
So just remove the ss_kbhit(), but keep the break, so that you can stop your program via the web page, like
#include "midas.h"
#include "stdio.h"
int main() {
cm_connect_experiment("", "", "logic_controller", NULL);
do {
int status = cm_yield(100);
printf("cm_yield returned %d\n", status);
if (status == SS_ABORT || status == RPC_SHUTDOWN)
break;
} while (TRUE);
cm_disconnect_experiment();
return 0;
} |
2152
|
14 Apr 2021 |
Stefan Ritt | Suggestion | Time zone selection for web page | > The new history as well as the clock in the web page header show the local time
> of the user's computer running the browser.
> Would it be possible to make it either always use the time zone of the Midas
> server, or make it selectable from the config page?
> It's not ideal trying to relate error messages from the midas.log to history
> plots if the time stamps don't match.
I implemented a new row in the config page to select the time zone.
"Local": Time zone where the browser runs
"Server": Time zone where the midas server runs (you have to update mhttpd for that)
"UTC+X": Any other time zone
The setting affects both the status header and the history display.
I spent quite some time with "named" time zones like "PST" "EST" "CEST", but the
support for that is not that great in JavaScript, so I decided to go with simple
UTC+X. Hope that's ok.
Please give it a try and let me know if it's working for you.
Best,
Stefan |
Attachment 1: Screenshot_2021-04-14_at_16.54.12_.png
|
|
|