Back Midas Rome Roody Rootana
  Midas DAQ System, Page 118 of 136  Not logged in ELOG logo
New entries since:Wed Dec 31 16:00:00 1969
ID Date Authorup Topic Subject
  1978   10 Aug 2020 Stefan RittBug Reportdata missing in runXXXXXX.mid
I have to reproduce the problem to fix it. Why don't you go and modify midas/examples/experiment/frontend.cxx in such a way that 
it creates exactly the banks you have, just with random data. If you see the same problem, send me your frontend file so that I 
can reproduce it.
  1982   13 Aug 2020 Stefan RittSuggestionadding db_get_mode ti check access mode for keys
> Hello,
> 
> I am wondering if there is a function that checks the access mode for a key? I 
> found the db_set_mode() function that allows me to set the access mode for a key, 
> but failed to find its counterpart get function.
> 
> Thanks in advance,
> Yan


  KEY k;
  db_get_key(hDB, handle, &k);
  std::cout << k.access_mode << std::endl;

/Stefan
  1985   24 Aug 2020 Stefan RittForumtime information
> 1. Is it possible to get "Running time" using, for example, jsonrpc? (please see 
> the attached file)

You have in the ODB "/Runinfo/Start time binary" which is measured in seconds since 
1970. By subtracting this from the current time, you get the running time.

> 2. Is it possible to configure "Start time" and "Stop time" with time zone? For 
> example when I start a new run, value of "Start time" key is automatically changed 
> to "Fri Aug 21 12:38:36 2020" without time zone. 

"Start time binary" and "Stop time binary" are in seconds since the 1970 in UTC, so no 
time zone involved there. The ASCII versions of the start/stop time are derived from 
the binary time using the server's local time zone. If you want to display them in a 
different time zone, you have to create a custom page and convert it to another time 
zone using JavaScript like

var d = new Date(start_time_binary);

Stefan
  2007   20 Oct 2020 Stefan RittInfoAbout remote control of front end part of MIDAS on chip
We also use a Zynq chip and boot in the following order:

1. SD Card
   a. First Stage Bootloader
   b. PL Firmware
   c. UBOOT
2. NFS over Ethernet
   a. Linux kernel
   b. RootFS
   c. Mounting home directories


If you need details I can bring you in contact with the person who actually implemented that.

Best,
Stefan
  2014   17 Nov 2020 Stefan RittInfoEquipment "common" settings in ODB
Today I addressed a topic which bugged me since long time. The ODB contains 
settings under /Equipment/<name>/Common which are a "mirror" of the equipment[] 
setting in a frontend (using the mfe.cxx framework). If the "Common" entry in 
the ODB is not present (fresh experiment), the equipment[] settings from the 
frontend are copied to the ODB. But if it exists, it takes precedence over the 
equipment[] entries, which is wrong in my opinion. Like if you change some 
settings in equipment[] (like the logging period of the history), then recompile 
and restart the frontend, the old values in the ODB are kept and your 
modification in the frontend code has no effect.

Starting on commit c3017c6c on Nov. 17th 2020 I reversed the precedence: Now, on 
each start of the frontend program, the values from equipment[] are written to 
the ODB. They are still "live". If one changes them when the frontend is 
running, that change takes effect immediately. But on the next restart of the 
frontend, the old values from equipment[] is put back there.

I fell too many times into this trap, and I hope the modification helps 
everybody. If there are however experiments which rely on the fact that the 
common settings in the ODB are NOT overwritten by the frontend, please let me 
know and I can put a flag "EQUIPMENT_FE_PRECEDENCE = FALSE" somewhere to restore 
the old behaviour.

Stefan
  2016   19 Nov 2020 Stefan RittForumHistory plot consuming too much memory
The history code is right now programmes in such a way that when you request
an old time window, then all data from that window until the present date
gets loaded. When we implemented that, this worked fine for data ranges of 
several years with a delay of just a few seconds. Of course one can only
load that specific window, but when the user then scrolls right, one has to
append new data to the "right side" of the array stored in the browser. If the
user jumps to another location, then the browser has to keep track of which 
windows are loaded and which windows not, making the history code much more 
complicated. Therefore I'm only willing to spend a few days of solid work
if this really becomes a problem. 

Are you sure that the delay comes from the browser or actually from mhttpd
digging through GBytes of history data? I realized that you need solid state
disks to get a real quick response.

Stefan
  2018   20 Nov 2020 Stefan RittForumHistory plot consuming too much memory
 > Taking this down a tangent, I have a mild concern that a user could temporarily 
> flood our gigabit network if we do have faster disks to read the history data. Have 
> there been any plans or thoughts on limiting the bandwidth users can pull from 
> mhttpd?

I guess this will not be network limiting but CPU limiting of the mhttpd process. But I'm 
not 100% sure, depends on the actual hardware. But even if we improve the history 
retrieval to "window only", the user could request all data form 2010 to 2020. So one 
would need some code which estimates the amount of data, then tell the user "do you really 
want that?". But still, a novice user can simply click "yes" without much of a thought. So 
in conclusion I believe proper user training is better than software limits. Like the 
other guy "I did 'rm -rf /', and now nothing works any more, can you help?".

Stefan
  2036   27 Nov 2020 Stefan RittInfoEquipment "common" settings in ODB
Ok, so what about the following proposal:

- I change back the mfe.cxx code to behave like before (ODB has precedence and does not get overwritten when the 
front-end restarts)

- I add a global flag

BOOL equipment_common_overwrite;

and pre-set it to FALSE;

- So if nothing is changed the flag stays false and ODB keeps precedence

- If a frontend wants to overwrite equipment/common on each start, the user sets

BOOL equipment_common_overwrite = TRUE;

near the equipment[] structure in the front-end code. 

- If the flag is true, the mfe.cxx init code copies the equipment[] structure to the ODB on each frontend start

I believe this way we can keep backward compatibility, and add the new way with minimal effort. The only downside 
is that all frontends on this plane have to add at least "BOOL equipment_common_overwrite = FALSE;" in their 
code.

I know global variables are evil, but this way the user can just add the line above to the equipment[] array, so 
one sees this when one edits the equipment[] array, giving motivation to change as needed. So the code would be



BOOL equipment_common_overwrite = TRUE;

EQUIPMENT equipment[] = {
 ....
}



An alternative way would be to add a function

  set_equipment_common_overwrite(TRUE);

into the frontend_init() code. That's somehow cleaner (still needs an internal global variable), but it has to go 
into frontend_init() so won't be at the same place as the EQUIPMENT list in the frontend.

Thoughts?

Best,
Stefan
  2039   30 Nov 2020 Stefan RittInfoEquipment "common" settings in ODB
Ok, I implemented it the following way:

- Added a boolean flag "equipment_common_overwrite", which must be contained in EACH frontend, preferably just 
before the EQUIPMENT structure, such as:

BOOL equipment_common_overwrite = TRUE;

EQUIPMENT equipment[] = {
...
};

- If that flag is TRUE, then the contents of the "equipment" structure is copied to the ODB on each start of the 
front-end

- If the flag is FALSE, then the ODB values are kept on the start of the front-end

The setting of the flag depends now on the philosophy of the experiment. Some experiments say that everything 
needed should be in the front-end code, so when it starts everything gets set correctly. They don't change the 
values in the ODB, but in the frontend code, which then goes into their repository. Other experiments just need 
some default values from the frontend code, and the fine-tune things by changing values in the ODB. These 
experiments should set this flag to FALSE.

*****

Please note that EVERY frontend now needs this flag, so all of you have to add it to all of your front-ends, 
otherwise the front-end will not compile! I could not figure out how to this could be done without this 
requirement, since you can define a global variable only once.

*****


Stefan
  2040   30 Nov 2020 Stefan RittSuggestionODBSET wildcards with array keys in Sequencer files
Hi Konstantin,

we are considering to make the range selection uniform among json, sequencer and 
odbedit "set" command. Having multiple ranges like [1,4-5] will be quite some work, so 
my question is did you just implement it on the json side because it was easy, or are 
there experiments who really need it? Wouldn't it be enough to have

[*]
[n]
[n-m]

This way we always have only one db_set_data() value behind that. Any set of indices 
we have to split into several db_set_data(), which especially for the front-end 
configuration can cause trouble by triggering a hot link on each access.

Stefan
  2041   30 Nov 2020 Stefan RittInfoEquipment "common" settings in ODB
One more change: 

After using the new code for some hours, we realized that the "enabled" flag should not come from the frontend code, 
but always be defined by the ODB. So if you quickly have to disable some equipment because the associated hardware is 
off, you want to change this flag only in the ODB and not have to recompile the frontend. So we exclude that flag from 
being set by the frontend. It is anyhow special, because one sees all disable equipment in the main midas status page, 
so one knows what's on and what's off.

Please comment here if you think that change causes problem. Anyhow it's working now for the enabled flag as before 
all these changes.

Stefan
  2046   01 Dec 2020 Stefan RittForumsubrun
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 RittForumhistory 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 RittForumIssues 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 RittSuggestionCode 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 RittSuggestionCode 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 RittBug ReportLogger: 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 RittSuggestionImproving 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 RittForumhistory 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 RittForumpoll_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
ELOG V3.1.4-2e1708b5