Back Midas Rome Roody Rootana
  Midas DAQ System, Page 69 of 142  Not logged in ELOG logo
ID Date Author Topicdown Subject
  1628   23 Jul 2019 Frederik WautersForumHow to convert C midas frontends to C++
> Did you include mfe.h as written in elog:1526 ?
> 
> Stefan


Yes I did

this is my include 

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <pthread.h>


#include "midas.h"
#include "mscb.h"
#include "multi.h"
#include "mscbdev.h"
#include "mfe.h"

(I attach my dummy fe)

What confuses me is that I can compile examples/experiment/ if I copy that to a 
fresh dir.

I also copied the CMakeLists from the example:

#
# cmake for the muX software
#
cmake_minimum_required(VERSION 3.3)

project(muX)

#
# find midas installation, from CMakeLists in examples/experiment
#
set(MIDAS_DIR $ENV{MIDASSYS})
message("MIDAS dir: " ${MIDAS_DIR})
if (NOT EXISTS $ENV{MIDASSYS})
  message(FATAL_ERROR "Environment variable $MIDASSYS not defined, aborting.")
endif()

set(INC_PATH ${MIDAS_DIR}/include ${MIDAS_DIR}/mxml ${MIDAS_DIR}/mscb/include 
${MIDAS_DIR}/drivers/class ${MIDAS_DIR}/drivers/device)
link_directories($ENV{MIDASSYS}/lib)

# enable certain compile warnings
add_compile_options(-Wall -Wformat=2 -Wno-format-nonliteral -Wno-strict-
aliasing -Wuninitialized -Wno-unused-function)

set(LIBS -lpthread -lutil -lrt) 


add_executable(sc_fe_mini sc_fe_mini.cpp)
target_include_directories(sc_fe_mini PRIVATE ${INC_PATH})
target_link_libraries(sc_fe_mini mfe midas ${LIBS})
Attachment 1: sc_fe_mini.cpp
/********************************************************************\
 
 Name:         sc_fe.c
 Created by:   Stefan Ritt
 		Frederik Wauters
 		Andreas Knecht
 
 Contents:     Slow control frontend for the muX  experiment
 
 $Id: sc_fe.c 21520 2014-11-03 12:03:56Z ritt $
 
 \********************************************************************/

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <pthread.h>


#include "midas.h"
#include "mscb.h"
#include "multi.h"
#include "mscbdev.h"
#include "mfe.h"

/*-- Globals -------------------------------------------------------*/

/* The frontend name (client name) as seen by other MIDAS clients   */
const char *frontend_name = "SC Frontend";
/* The frontend file name, don't change it */
const char *frontend_file_name = __FILE__;

/* frontend_loop is called periodically if this variable is TRUE    */
BOOL frontend_call_loop = TRUE;

/* a frontend status page is displayed with this frequency in ms    */
INT display_period = 0;//1000;

/* maximum event size produced by this frontend */
INT max_event_size = 5*100000;

/* maximum event size for fragmented events (EQ_FRAGMENTED) */
INT max_event_size_frag = 5 * 1024 * 1024;

/* buffer size to hold events */
INT event_buffer_size = 2 *5* 100000;




/*-- Equipment list ------------------------------------------------*/

/* device driver list */


// New HV power supply with "many" channels
DEVICE_DRIVER hv_driver[] = {
    {"64xHV-PSI", mscbdev, 0, NULL, DF_MULTITHREAD},
    {""}
};


/*DEVICE_DRIVER cfd_driver[] = {
    {"CFD-950", mscbdev, 0, NULL, DF_INPUT | DF_MULTITHREAD},
    {""}
};

DEVICE_DRIVER pressure_driver[] = {
    {"PFEIFFER", mscbdev, 0, NULL, DF_INPUT | DF_MULTITHREAD},
    {""}
};

DEVICE_DRIVER multi_driver[] = {
    {"ADC", mscbdev, 0, NULL, DF_INPUT | DF_MULTITHREAD},
    {""}
};

DEVICE_DRIVER autofill_A_driver[] = {
    {"Input", mscbdev, 0, NULL, DF_INPUT | DF_MULTITHREAD},
    {"Output", mscbdev, 0, NULL, DF_OUTPUT | DF_MULTITHREAD},
    {""}
};

DEVICE_DRIVER autofill_B_driver[] = {
    {"Input", mscbdev, 0, NULL, DF_INPUT | DF_MULTITHREAD},
    {"Output", mscbdev, 0, NULL, DF_OUTPUT | DF_MULTITHREAD},
    {""}
};

// HV device with hardware ramp and 1 channel per node
DEVICE_DRIVER poshv_driver[] = {
   {"PMT", mscbhvr, 0, NULL, DF_HW_RAMP | DF_PRIO_DEVICE | DF_MULTITHREAD},
   {""}
};*/

EQUIPMENT equipment[] = {
    
    

    
    {"SiPM_HV",                       /* equipment name */
        {10, 0,                     /* event ID, trigger mask */
            "SYSTEM",                  /* event buffer */
            EQ_SLOW,                   /* equipment type */
            0,                         /* event source */
            "MIDAS",                   /* format */
            TRUE,                      /* enabled */
            RO_ALWAYS,
            60000,                     /* produce event every 60 sec */
            1000,                      /* read one event every second */
            0,                         /* number of sub events */
            1,                        /* log history every 10 seconds event */
            "", "", ""} ,
        cd_multi_read,                 /* readout routine */
        cd_multi,                      /* class driver main routine */
        hv_driver,                  /* device driver list */
        NULL,                       /* init string */
    },
    
    
    //    {"CFD",                     /* equipment name */
    //    {11, 0,                     /* event ID, trigger mask */
    //     "SYSTEM",                  /* event buffer */
    //     EQ_SLOW,                   /* equipment type */
    //     0,                         /* event source */
    //     "MIDAS",                   /* format */
    //     TRUE,                      /* enabled */
    //     RO_ALWAYS,
    //     60000,                     /* read every 60 sec */
    //     1000,                      /* read one event every second */
    //     0,                         /* number of sub events */
    //     1,                         /* log history every second */
    //     "", "", ""} ,
    //    cd_multi_read,              /* readout routine */
    //    cd_multi,                   /* class driver main routine */
    //    cfd_driver,                 /* device driver list */
    //    NULL,                       /* init string */
    //    },
    
    //   {"Pressures",                /* equipment name */
    //    {12, 0,                     /* event ID, trigger mask */
    //     "SYSTEM",                  /* event buffer */
    //     EQ_SLOW,                   /* equipment type */
    //     0,                         /* event source */
    //     "MIDAS",                   /* format */
    //     TRUE,                      /* enabled */
    //     RO_ALWAYS,
    //     60000,                     /* read every 60 sec */
    //     1000,                      /* read one event every second */
    //     0,                         /* number of sub events */
    //     1,                         /* log history every second */
    //    "", "", ""} ,
    //    cd_multi_read,              /* readout routine */
    //    cd_multi,                   /* class driver main routine */
    //    pressure_driver,            /* device driver list */
    //    NULL,                    
    
    {""}
};

/*-- Dummy routines ------------------------------------------------*/

INT poll_event(INT source[], INT count, BOOL test)
{
    return 1;
};
INT interrupt_configure(INT cmd, INT source[], PTYPE adr)
{
    return 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++)
      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) {
     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 Input", equipment);
      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++;
}

void scfe_error(const char *error)
{
    char str[256];
    
    strlcpy(str, error, sizeof(str));
    cm_msg(MERROR, "scfe_error", "%s", str);
    al_trigger_alarm("MSCB", str, "MSCB Alarm", "Communication Problem", AT_INTERNAL);
}

/*-- Frontend Init -------------------------------------------------*/

INT frontend_init()
{
    HNDLE hDB;
    //int i, im, iv;
    //char str[80];
    
    cm_get_experiment_database(&hDB, NULL);
    
    /* set error dispatcher for alarm functionality */
    mfe_set_error(scfe_error);
    
    /* set maximal retry count */
    mscb_set_max_retry(100);
    

    
    /* HV */
    // New SiPM power supply with many channels
    mscb_define("mscb267.psi.ch", "SiPM_HV", "64xHV-PSI", hv_driver, 1, 0, "Temperature 1", 0.1);
        
    return CM_SUCCESS;
}

/*-- Frontend Exit -------------------------------------------------*/

INT frontend_exit()
{
    return CM_SUCCESS;
}

/*-- Begin of Run --------------------------------------------------*/

INT begin_of_run(INT run_number, char *error)
{
    return CM_SUCCESS;
}

/*-- End of Run ----------------------------------------------------*/

INT end_of_run(INT run_number, char *error)
{
    return CM_SUCCESS;
}

/*-- Pause Run -----------------------------------------------------*/

INT pause_run(INT run_number, char *error)
{
    return CM_SUCCESS;
}

/*-- Resuem Run ----------------------------------------------------*/

INT resume_run(INT run_number, char *error)
{
    return CM_SUCCESS;
}

/*-- Frontend Loop -------------------------------------------------*/

INT frontend_loop()
{
... 6 more lines ...
  1629   23 Jul 2019 Stefan RittForumHow to convert C midas frontends to C++
Have you left any "extern C" in your frontend program or in any of the used header file. Seems 
like the linker cannot find the poll_event in your frontend code. If it's there, but it's compiled 
with C calling (instead of C++), the name mangling causes it to be invisible to the linker. That 
usually happens if there is somewhere

extern C {
  INT poll_event();
  ... 
}

while it is NOT defined as "extern C" in mfe.h which is used by mfe.cxx.

Stefan

> > Did you include mfe.h as written in elog:1526 ?
> > 
> > Stefan
> 
> 
> Yes I did
> 
> this is my include 
> 
> #include <stdio.h>
> #include <string.h>
> #include <assert.h>
> #include <math.h>
> #include <pthread.h>
> 
> 
> #include "midas.h"
> #include "mscb.h"
> #include "multi.h"
> #include "mscbdev.h"
> #include "mfe.h"
> 
> (I attach my dummy fe)
> 
> What confuses me is that I can compile examples/experiment/ if I copy that to a 
> fresh dir.
> 
> I also copied the CMakeLists from the example:
> 
> #
> # cmake for the muX software
> #
> cmake_minimum_required(VERSION 3.3)
> 
> project(muX)
> 
> #
> # find midas installation, from CMakeLists in examples/experiment
> #
> set(MIDAS_DIR $ENV{MIDASSYS})
> message("MIDAS dir: " ${MIDAS_DIR})
> if (NOT EXISTS $ENV{MIDASSYS})
>   message(FATAL_ERROR "Environment variable $MIDASSYS not defined, aborting.")
> endif()
> 
> set(INC_PATH ${MIDAS_DIR}/include ${MIDAS_DIR}/mxml ${MIDAS_DIR}/mscb/include 
> ${MIDAS_DIR}/drivers/class ${MIDAS_DIR}/drivers/device)
> link_directories($ENV{MIDASSYS}/lib)
> 
> # enable certain compile warnings
> add_compile_options(-Wall -Wformat=2 -Wno-format-nonliteral -Wno-strict-
> aliasing -Wuninitialized -Wno-unused-function)
> 
> set(LIBS -lpthread -lutil -lrt) 
> 
> 
> add_executable(sc_fe_mini sc_fe_mini.cpp)
> target_include_directories(sc_fe_mini PRIVATE ${INC_PATH})
> target_link_libraries(sc_fe_mini mfe midas ${LIBS})
  1630   23 Jul 2019 Lukas GerritzenForumHow to convert C midas frontends to C++
Can you post the exact command that cmake executes to link sc_fe_mini (with make VERBOSE=1)?

I have noticed similar linking problems that depended on the order when linking. In my case, it 
compiled when "-lpthread -lutil -lrt" were at the end of the command, but not before mfe.o and 
libmidas.a. Unfortunately I haven't found a way to tell cmake the "correct" order of the link 
libraries.

Maybe this can be fixed by adding midas as a subdirectory in your cmake project and just linking 
against the "mfe" target instead of libmfe.a.
  1633   25 Jul 2019 Frederik WautersForumHow to convert C midas frontends to C++ (my problem solved)
Ok, so the detail that I missed was that the dummy functions

INT poll_event(INT source[], INT count, BOOL test)
{
   return 1;
};

as shown in some of the older examples, work when you set

INT poll_event(INT source, INT count, BOOL test)
{
   return 1;
};


as a side comment, not all drivers are c++ compatible yet (e.g. mscbvr), so changes needed are small 
  1637   30 Jul 2019 Stefan RittForumHow to convert C midas frontends to C++ (my problem solved)
> as a side comment, not all drivers are c++ compatible yet (e.g. mscbvr), so changes needed are small 

Right. We recently switched the whole midas to c++, but we could not cover all drivers. Most of them just need some type 
casting to compile under c++. I got already patches from several people which I'm happy to merge in. If you got mscbhvr 
or any other driver compile under c++, please send me the diff.

Stefan
  1639   01 Aug 2019 Stefan RittForumHow to convert C midas frontends to C++ (my problem solved)
> 
> Ok, so the detail that I missed was that the dummy functions
> 
> INT poll_event(INT source[], INT count, BOOL test)
> {
>    return 1;
> };
> 
> as shown in some of the older examples, work when you set
> 
> INT poll_event(INT source, INT count, BOOL test)
> {
>    return 1;
> };

If you would have read elog:1526 more carefully (point a4) you would have saved yourself a lot of time.

Stefan
  1641   06 Aug 2019 Thomas LindnerForumMIDAS Workshop on Aug 7
Dear MIDAS users,

A final reminder about the MIDAS workshop tomorrow.  A couple reminders/notes: 

1) Workshop will take place from 1PM-5:30PM (Vancouver time) on Aug 7.

2) A finalized agenda for the workshop is posted here:

https://indico.triumf.ca/conferenceDisplay.py?confId=2438

Speakers should email me their talks beforehand and I will post them.

3) For those who want to participate remotely, we will be using bluejeans.  The webpage for the bluejeans meeting is here:
 
https://bluejeans.com/462865444

I will start the connection ~20min before the start of the session; people calling in remotely might want to call early, so we can test the sound quality.

4) For those at TRIUMF, the meeting will be in the ISAC-II conference room.

Thomas
 

> Dear MIDAS users,
> 
> Here's further information on the third MIDAS workshop:
> 
> 1) Workshop will take place from 1PM-5PM (Vancouver time) on Aug 7.
> 
> 2) A mostly finalized agenda for the workshop is posted here:
> 
> https://indico.triumf.ca/conferenceDisplay.py?confId=2438
> 
> People are still welcome to email me if they want to present something.  We should be able to add it to the schedule.
> 
> 3) For those who want to participate remotely, we will be using bluejeans.  The webpage for the bluejeans meeting is here:
> 
> https://bluejeans.com/462865444
> 
> 4) For those at TRIUMF I will confirm the meeting room closer to the date.
> 
> Thomas
> 
> 
> > Dear MIDAS users,
> > 
> > We would like to announce a third MIDAS workshop at TRIUMF on Aug 7, 2019.
> > Stefan Ritt will again be visiting TRIUMF at this time.
> > 
> > The overall goal of the workshop is to present new features in MIDAS, to discuss
> > future changes and to hear experiences from different experiments.
> > 
> > We expect that some participants will connect remotely to the workshop; we will
> > setup a video-conferencing option.  The exact time of the workshop will be
> > decided later and will be optimized based on the geographic distribution of
> > remote attendees. So please let us know if you want to attend remotely.  We are
> > also happy for people to come in person to TRIUMF.  
> > 
> > A (very) preliminary agenda includes
> > 
> > - New default mhttpd pages and new APIs for custom pages
> > - Conversion of MIDAS to C++
> > - new C++ based frontend framework (tmfe and mvodb from ALPHA-g)
> > - MySQL/Postgres database for storing ODB configurations
> > - Plans for updating history plotting
> > - Using MIDAS with an online trigger farm
> > - new C++ multithreaded flow analyzer (manalyzer from ALPHA-g)
> > 
> > But please suggest other topics; we also hope to hear reports from particular
> > experiments.
> > 
> > Sincerely,
> > Thomas (on behalf of MIDAS developers)
  1659   09 Aug 2019 Konstantin OlchanskiForumHow to convert C midas frontends to C++
> How do I solve mismatched declarations in the mfe (or other places in the midas code)?

I run into such problems all the time. My solution? I grep for the function name in my code and in the header file,
then look very carefully at the definition to confirm that all the argument declarations are the same in both
places. Sometimes my eyes do not see the difference and I ask for a "second pair of eyes".

In your case, you have a mismatch between functions in mfe.h and in your frontend. The difference
is "int source" in mfe.h and "int source[]" in your code.

Because C++ permits functions with identical namesm but different arguments, the compiler thinks
you did this on purpose and does not complain. Later, of course, the linker bombs,
but all it can report at this stage, is what you see "function not found"... Then you grep your code
for the missing function, check arguments, rinse, repeat.

Before C++, the C compiler would probably had complained about the mismatch, except that MIDAS
did not have an mfe.h header file definitions for all this stuff until just now, so again, the mismatch would
have gone unnoticed, unfixed.

K.O.



> It is having issues with the midas defined BOOL/... types. This 
> is what I get for a minimal scfe:
> 
> [ 12%] Building CXX object CMakeFiles/sc_fe_mini.dir/sc_fe_mini.cpp.o
> [ 25%] Building CXX object CMakeFiles/sc_fe_mini.dir/home/frederik/packages/midas/drivers/class/hv.cxx.o
> [ 37%] Building CXX object CMakeFiles/sc_fe_mini.dir/home/frederik/packages/midas/drivers/class/multi.cxx.o
> [ 50%] Building CXX object CMakeFiles/sc_fe_mini.dir/home/frederik/packages/midas/drivers/device/nulldev.cxx.o
> [ 62%] Building CXX object CMakeFiles/sc_fe_mini.dir/home/frederik/packages/midas/drivers/bus/null.cxx.o
> [ 75%] Building CXX object CMakeFiles/sc_fe_mini.dir/home/frederik/packages/midas/drivers/device/mscbdev.cxx.o
> [ 87%] Building CXX object CMakeFiles/sc_fe_mini.dir/home/frederik/packages/midas/mscb/src/mscb.cxx.o
> [100%] Linking CXX executable sc_fe_mini
> /home/frederik/packages/midas/build/libmfe.a(mfe.cxx.o): In function `_readout_thread':
> /home/frederik/packages/midas/src/mfe.cxx:1271: undefined reference to `poll_event(int, int, unsigned int)'
> /home/frederik/packages/midas/build/libmfe.a(mfe.cxx.o): In function `check_polled_events':
> /home/frederik/packages/midas/src/mfe.cxx:1601: undefined reference to `poll_event(int, int, unsigned int)'
> /home/frederik/packages/midas/src/mfe.cxx:1643: undefined reference to `poll_event(int, int, unsigned int)'
> /home/frederik/packages/midas/build/libmfe.a(mfe.cxx.o): In function `readout_enable(unsigned int)':
> /home/frederik/packages/midas/src/mfe.cxx:1158: undefined reference to `interrupt_configure(int, int, long)'
> /home/frederik/packages/midas/src/mfe.cxx:1156: undefined reference to `interrupt_configure(int, int, long)'
> /home/frederik/packages/midas/build/libmfe.a(mfe.cxx.o): In function `initialize_equipment':
> /home/frederik/packages/midas/src/mfe.cxx:614: undefined reference to `interrupt_configure(int, int, long)'
> /home/frederik/packages/midas/src/mfe.cxx:649: undefined reference to `poll_event(int, int, unsigned int)'
> /home/frederik/packages/midas/build/libmfe.a(mfe.cxx.o): In function `scheduler':
> /home/frederik/packages/midas/src/mfe.cxx:1890: undefined reference to `poll_event(int, int, unsigned int)'
> /home/frederik/packages/midas/src/mfe.cxx:1932: undefined reference to `poll_event(int, int, unsigned int)'
> /home/frederik/packages/midas/build/libmfe.a(mfe.cxx.o): In function `main':
> /home/frederik/packages/midas/src/mfe.cxx:2701: undefined reference to `interrupt_configure(int, int, long)'
> /home/frederik/packages/midas/src/mfe.cxx:2702: undefined reference to `interrupt_configure(int, int, long)'
> collect2: error: ld returned 1 exit status
> make[2]: *** [sc_fe_mini] Error 1
> make[1]: *** [CMakeFiles/sc_fe_mini.dir/all] Error 2
> make: *** [all] Error 2
> 
> 
> This is my cmakelists for my user code:
> 
> #
> # cmake for the muX software
> #
> cmake_minimum_required(VERSION 3.3)
> 
> project(muX)
> 
> #
> # find installations
> #
> set(MIDAS_DIR $ENV{MIDASSYS})
> message("MIDAS dir: " ${MIDAS_DIR})
> 
> #
> # set directories
> #
> set(MIDASBUILD_DIR ${MIDAS_DIR}/build)
> set(MIDASINCLUDE_DIR ${MIDAS_DIR}/include)
> set(MXML_DIR ${MIDAS_DIR}/mxml)
> set(MSCB_DIR ${MIDAS_DIR}/mscb)
> set(DRV_DIR ${MIDAS_DIR}/drivers)
> 
> 
> #
> # drivers, libs
> #
> set(DRIVERS
>     ${MIDAS_DIR}/drivers/class/hv
>     ${MIDAS_DIR}/drivers/class/multi
>     ${MIDAS_DIR}/drivers/device/nulldev
>     ${MIDAS_DIR}/drivers/bus/null
> )
> set(MIDASLIB ${MIDASBUILD_DIR}/libmidas.a)
> set(FELIB ${MIDASBUILD_DIR}/libmfe.a)
> 
> #
> # sc_fe
> #
> add_executable(sc_fe_mini
>         sc_fe_mini.cpp
>         ${DRIVERS}
>         ${MIDAS_DIR}/drivers/device/mscbdev
>         ${MIDAS_DIR}/mscb/src/mscb)
> 
> target_include_directories(sc_fe_mini PRIVATE ${DRV_DIR} ${MIDAS_DIR}/mscb/include ${MIDAS_DIR}/include)
> target_link_libraries(sc_fe_mini ${LIBS} ${MIDASLIB} ${FELIB} rt pthread util)
> 
> 
> 
> I seem to be able to compile the current midas distributions, including the scfe frontend
> 
> 
> 
> > To convert a MIDAS frontend to C++ follow this checklist:
> > 
> > a) add #include "mfe.h" after include of midas.h and fix all compilation errors.
> > 
> > NOTE: there should be no "extern C"  brackets around MIDAS include files.
> > 
> > NOTE: Expect to see following problems:
> > 
> > a1) duplicate or mismatched declarations of functions defined in mfe.h
> > a2) frontend_name and frontend_file_name should be "const char*" instead of "char*"
> > a3) duplicate "HNDLE hDB" collision with hDB from mfe.c - not sure why it worked before, either use HNDLE hDB from mfe.h or use "extern HNDLE hDB".
> > a4) poll_event() and interrupt_configure() have "source" as "int[]" instead of "int" (why did this work before?)
> > a5) use of "extern int frontend_index" instead of get_frontend_index() from mfe.h
> > a6) bk_create() last argument needs to be cast to (void**)
> > a7) "bool debug" collides with "debug" from mfe.h (why did this work before?)
> > 
> > b) remove no longer needed "extern C" brackets around mfe related code. Ideally there should be no "extern C" brackets anywhere.
> > 
> > c) in the Makefile, change CC=gcc to CC=g++ for compiling and linking everything as C++
> > 
> > c1) fix all compilation problems. most valid C code will compile as valid C++, but there is some known trouble:
> > - return value of malloc() & co needs to be cast to the correct data type: "char* s = (char*)malloc(...)"
> > - some C++ compilers complain about mismatch between signed and unsigned values
> > 
> > If you need help with converting your frontend from C to C++, I will be most happy
> > to assist you - post your compiler error messages to this forum or email them to me privately.
> > 
> > Good luck,
> > K.O.
  1665   28 Aug 2019 Nick HastingsForumHistory plot problems for frontend with multiple indicies
Hello experts,

I have been writing a SC frontend for a powersupply. I have used the model 
where the frontend can be started with "-i n" option so that each fe can 
control a different supply. During the development/testing of the program I 
would normally only run a single instance with "-i 1". However when I started
a second instance with "-i 2" I found problems with the history plots that
were being made for the original "-i 1" instance. The variable being plotted
seemed to randomly jump between the value from the "-i 1" instance and 
the "-i 2" instance.  confirmed that the "correct" values exist for each 
frontend in the odb under /Equipment/Foo01/Variables and 
/Equipment/Foo02/Variables

This is also not just a plotting artifact since I was also
able to see the two different values by running mhist.

I saw this behaviour using midas-2019-03 and also the head of the development
branch (686e4de2b55023b0d1936c60bcf4767c5e6caac0 from just under 48 hours ago). 

I was able to reproduce this with a stripped down frontend that just 
sets a variable that is equal to its frontend_index. Please find the code 
and Makefile attached. Presumably I've done something wrong in my 
implementation that hopefully a more experienced person can spot quite 
quickly, but please let me know if any more information is needed.

I have seen this behaviour on both Debian 10 and on a CentOS 7 Singularity 
image running on top of Debian 10.

Thanks,

Nick.

P.S. I made the topic of this post "Forum" and not "Bug Report" since I
expect the root of this problem is somewhere between the keyboard and chair.
Attachment 1: fedummy.cxx
/*******************************************************************\

  Name:         fetest.cxx
  Created by:   

  Contents:     Front end for testing MIDAS. Just sets a variable to
                the value of the frontend index.

\********************************************************************/

#undef NDEBUG // midas required assert() to be always enabled

#include <cassert>
#include "mfe.h"

/*-- Globals -------------------------------------------------------*/

/* The frontend name (client name) as seen by other MIDAS clients   */
const char *frontend_name = "fedummy";

/* The frontend file name, don't change it */
const char *frontend_file_name = __FILE__;

/* frontend_loop is called periodically if this variable is TRUE    */
BOOL frontend_call_loop = FALSE;

/* a frontend status page is displayed with this frequency in ms */
INT display_period = 0;

/* maximum event size produced by this frontend */
INT max_event_size      = 4*1024*1024;
INT max_event_size_frag = 4*1024*1024;

/* buffer size to hold events */
INT event_buffer_size = 10*1024*1024;

/*-- Function declarations -----------------------------------------*/

INT frontend_init();
INT frontend_exit();
INT begin_of_run(INT run_number, char *error);
INT end_of_run(INT run_number, char *error);
INT pause_run(INT run_number, char *error);
INT resume_run(INT run_number, char *error);
INT frontend_loop();
INT poll_event(INT source, INT count, BOOL test);
INT interrupt_configure(INT cmd, INT source, PTYPE adr);

int read_dummy_event(char *pevent, int off);

/*-- Equipment list ------------------------------------------------*/

#ifndef FE_NAME
#define FE_NAME "fedummy"
#endif

#ifndef EQ_NAME
#define EQ_NAME "Dummy"
#endif

#ifndef EQ_EVID
#define EQ_EVID 1
#endif

char eq_name[256];

EQUIPMENT equipment[] = {

  { EQ_NAME "%02d"   ,         /* equipment name */
    {
      EQ_EVID, (1<<EQ_EVID),/* event ID, trigger mask */
      "SYSTEM",             /* event buffer */
      EQ_PERIODIC,          /* equipment type */
      0,                    /* event source */
      "MIDAS",              /* format */
      TRUE,                 /* enabled */
      RO_ALWAYS,            /* Read when running */
      1000,                 /* poll every so milliseconds */
      0,                    /* stop run after this event limit */
      0,                    /* number of sub events */
      1,                    /* history period */
      "", "", ""
    },
    read_dummy_event,/* readout routine */
    NULL,
    NULL,
    NULL,       /* bank list */
  }
  ,
  {""}
};
int event_size = 10*1024;

/*-- Frontend Init -------------------------------------------------*/
#include "msystem.h"

INT frontend_init()
{
   sprintf(eq_name, "%s%02d", EQ_NAME, get_frontend_index());
   return SUCCESS;
}

INT frontend_exit()
{
   return SUCCESS;
}

INT begin_of_run(INT run_number, char *error)
{
   return SUCCESS;
}

INT end_of_run(INT run_number, char *error)
{
   return SUCCESS;
}

INT pause_run(INT run_number, char *error)
{
   return SUCCESS;
}

INT resume_run(INT run_number, char *error)
{
   return SUCCESS;
}

INT frontend_loop()
{
   return SUCCESS;
}

INT poll_event(INT source, INT count, BOOL test)
{
   return 0;
}

INT interrupt_configure(INT cmd, INT source, PTYPE adr)
{
  return 0;
}

INT read_dummy_event(char *pevent, INT off)
{
   static HNDLE hVar = 0;
   if ( hVar == 0 ) {
      char str[1024];
      sprintf(str, "/Equipment/%s/Variables", eq_name);
      
      int status = db_find_key(hDB, 0, str, &hVar);
      if ( status == DB_NO_KEY ) {
         status = db_create_key(hDB, 0, str, TID_KEY);
         if (status == DB_SUCCESS) {
            status = db_find_key(hDB, 0, str, &hVar);
         }
      }
      
      if (status != SUCCESS) {
         cm_msg(MERROR, frontend_name, "read_dummy_event: Can\'t find or create %s, status %d, exiting", str, status);
         exit(1);
      }
   }
   const float data = static_cast<float>(get_frontend_index());
   const int status = db_set_value( hDB, hVar, "Data", &data,
                          sizeof(float), 1, TID_FLOAT);
   assert(status == DB_SUCCESS);
   return 0;
}

/* emacs
 * Local Variables:
 * tab-width: 8
 * c-basic-offset: 3
 * indent-tabs-mode: nil
 * End:
 */
Attachment 2: Makefile
OSFLAGS  = -DOS_LINUX -Dextname
CFLAGS   = -g -O2 -fPIC -Wall -Wno-unused-function -I$(MIDASSYS)/include
CXXFLAGS = -std=c++11 $(CFLAGS)

LIBS = -lm -lz -lutil -lnsl -lpthread -lrt
MIDASLIBS = $(MIDASSYS)/lib/libmidas.a
MFE = $(MIDASSYS)/lib/mfe.o

all:: fedummy.exe

fedummy.exe: %.exe: fedummy.cxx $(MIDASLIBS) $(MFE)
	$(CXX) -o $@ $(CXXFLAGS) $(OSFLAGS) $^ $(MIDASLIBS) $(LIBS) -DFE_NAME=\"fedummy\" -DEQ_NAME=\"FeDummy\" -DEQ_EVID=1


%.o: %.cxx
	$(CXX) $(CXXFLAGS) $(OSFLAGS) -c $<

%.d: %.cxx
	$(CXX) -MM -MD $(CXXFLAGS) $(OSFLAGS) -c $<

depend:

-include *.d

clean::
	-rm -f *.o *.exe
	-rm -f *.d

  1666   28 Aug 2019 Stefan RittForumHistory plot problems for frontend with multiple indicies
My first question would be why are you using several font-ends at all? That makes things more 
complicated than needed. In the normal FE framework, you can define either several equipment 
served by one frontend, or even one equipment linked to several devices. In the MEG experiment 
we have one slow control frontend controlling ~100 devices without problem. In the old days there 
was a problem that some slow devices could throttle the readout, but since the invention of multi-
threaded slow control equipment, each device gets its own thread so they don't block each other.

Stefan
  1667   28 Aug 2019 Nick HastingsForumHistory plot problems for frontend with multiple indicies
Hi Stefan,

thanks for you quick reply.

> My first question would be why are you using several font-ends at all?

Becuase I was following the model used for many of the frontends for the ND280 FGD.

> That makes things more 
> complicated than needed. In the normal FE framework, you can define either several equipment 
> served by one frontend, or even one equipment linked to several devices. In the MEG experiment 
> we have one slow control frontend controlling ~100 devices without problem. In the old days 
there 
> was a problem that some slow devices could throttle the readout, but since the invention of 
multi-
> threaded slow control equipment, each device gets its own thread so they don't block each 
other.

Perhaps things have changed in the 10 years since the FGD SC code was written. I can do it 
differently but doing it that way seemed naturual since around 90% of the frontend code that I
have see does it that way.

Nick.
  1668   28 Aug 2019 lcpForumHistory plot problems for frontend with multiple indicies
hi, 

> > That makes things more 
> > complicated than needed. In the normal FE framework, you can define either several equipment 
> > served by one frontend, or even one equipment linked to several devices. In the MEG experiment 
> > we have one slow control frontend controlling ~100 devices without problem. In the old days 
> there 
> > was a problem that some slow devices could throttle the readout, but since the invention of 
> multi-
> > threaded slow control equipment, each device gets its own thread so they don't block each 
> other.
> 

I agree with Stefan, that it's probably better to run a multi-threaded setup, than individual frontends.

The only place I've ever used the frontend index on startup is when I was testing and building
an eventbuilder.

https://midas.triumf.ca/MidasWiki/index.php/Event_Builder#Example

This might explain, why your history is swapping between frontends, as in the event builder, it gets
reconstructed.

Maybe this helps...

LCP


> Perhaps things have changed in the 10 years since the FGD SC code was written. I can do it 
> differently but doing it that way seemed naturual since around 90% of the frontend code that I
> have see does it that way.
  1669   29 Aug 2019 Ben SmithForumHistory plot problems for frontend with multiple indicies
Hi Nick,

I confirm that this issue appears when using the MIDAS history driver. The issue does not appear when using the MYSQL history driver.

One solution is to give each frontend instance a different Event ID (see example code below for doing this in frontend_init). The history system did still seem to be confused by the existing FeDummy equipments/events even after making this change. However, after changing EQ_NAME from FeDummy to FeDum (i.e. starting from a clean state history-wise) things behaved normally.

I will note that some experiments definitely have a need for the "-i" method, especially those that run on distributed clusters.

Ben


```
INT frontend_init()
{
   sprintf(eq_name, "%s%02d", EQ_NAME, get_frontend_index());

   // Ensure each FE gets a different Event ID in the history system (951, 952 etc)
   char keyname[128];
   HNDLE hkey;
   int status;
   sprintf(keyname, "/Equipment/%s/Common/Event ID", eq_name);
   status = db_find_key(hDB, 0, keyname, &hkey);
   if (status != DB_SUCCESS) abort();

   WORD new_ev_id = 950 + get_frontend_index();
   status = db_set_data_index(hDB, hkey, &new_ev_id, 2, 0, TID_WORD);
   if (status != DB_SUCCESS) abort();
   return SUCCESS;
}
```
  Draft   29 Aug 2019 Nick HastingsForumHistory plot problems for frontend with multiple indicies
Hi LCP,

thanks for the suggestion and link. Unfortunatly I don't think this explains it.

Nick.
  Draft   29 Aug 2019 Nick HastingsForumHistory plot problems for frontend with multiple indicies
Hi Ben,

thanks for your reply. I can confirm that your suggested workaround does indeed
make the problem dissapear.

I guess this issue hasn't been seen at T2K since we use MYSQL for the history.

Thanks,

Nick.
  1672   01 Sep 2019 Nick HastingsForumHistory plot problems for frontend with multiple indicies
Hi Ben,

thanks for your reply. I can confirm that your suggested workaround does indeed
make the problem dissapear.

I guess this issue hasn't been seen at T2K since we use MYSQL for the history.

Thanks,

Nick.
  1676   06 Sep 2019 Pintaudi GiorgioForumOpen a hotlink to a single element in an ODB array
Hello!
Just a little question about the ODB hotlinks. Is it possible to open a hotlink
to a single element in and ODB array?
I have searched through the documentation and I have taken a look at the source
code but I could not find any piece of code to use as a reference (maybe I have
not searched deeply enough).

This is more or less what I would like to achieve (without error checking):
    for (INT i = 0; i < hv_info->num_channels; i++) {
      char element[HKEY_STRING_LENGTH];
      snprintf(element, HKEY_STRING_LENGTH, "%s[%d]", path, i);
      if (db_find_key(hDB, hv_info->hKeyRoot, element, &hKey) == DB_SUCCESS) {
        if ((hv_info->driver[i]->flags & flag) == 0) 
          db_open_record(hDB, hKey, &array[i], sizeof(double), MODE_READ, callback, pequipment);
        else
          db_open_record(hDB, hKey, &array[i], sizeof(double), MODE_READ, NULL, NULL);
      } else {
        cm_msg(MERROR, __func__, "Key %s not found", element);
      }
    }

But it is not working because the key is not found ...
Thank you
Giorgio
  1685   16 Sep 2019 Konstantin OlchanskiForumOpen a hotlink to a single element in an ODB array
> Is it possible to open a hotlink to a single element in an ODB array?

Not possible.

> sprintf(element, "%s[%d]", path, i);
> db_find_key(hDB, hv_info->hKeyRoot, element, &hKey);

There is some confusion and inconsistency between db_xxx() functions,
some of them accept the array index "a[10]" syntax, some do not.

db_find_key() and db_watch()/db_open_record() do not operate on array elements
and do not accept the "a[10]" array index syntax.

K.O.
  1689   16 Sep 2019 Konstantin OlchanskiForumHistory plot problems for frontend with multiple indicies
> My first question would be why are you using several font-ends at all? That makes things more 
> complicated than needed. In the normal FE framework, you can define either several equipment 
> served by one frontend, or even one equipment linked to several devices.

I am the culprit here, as I wrote the original code for T2K/ND280 that Nick is looking at.

At the time, we needed to control multiple units of identical equipment. Most of these equipments
needed to be controlled independently from each other, so we could not/did not want to use
one single frontend executable to control all of them at the same time. For example, for equipment
not in use, we can stop the corresponding frontend. In case of trouble, we can restart
the corresponding frontend without disrupting the frontends for the other equipments.

The successful operation of the T2K/ND280 experiment is sufficient defence for the validity of this approach.

One lesson learned was that the MIDAS frontend framework did not make it easy to have multiple identical frontends 
for controlling multiple identical equipments. (typical use is control of 2-3 Wiener power supplies, 1-2-3 UPS 
devices, etc). At the time (and today), only the "i NNN" flag is available to tell the frontend "who am I?". To make it 
work, one has to use the hard to "%02d" stuff in the equipment name, and there are other complications. For my 
"next generation" of frontends, I tried to specialize the frontend executables at compile time using C/C++ 
preprocessor defines (-Dwiener01, -Dwiener02, etc), this worked better, but still not super happy.

My current solution as implemented by the tmfe frontend framework is to give the user full control
over the command line arguments (mfe.c did not permit any "user arguments" and did not allow
access to argc/argv) and full control over the equipment names (mfe.c equipment names are fixed at compile time).

K.O.
  1691   16 Sep 2019 Konstantin OlchanskiForumHistory plot problems for frontend with multiple indicies
> it's probably better to run a multi-threaded setup, than individual frontends.

I recommend against using multiple threads if at all possible and unless absolutely required.

Only for one reason: multithreaded c++ programs are notoriously hard to debug.

In addition, one has to face several classes of bugs absent in single-threaded applications:

a) which thread "owns" which object
b) locking of all shared data
c) huge overheads from locking at high data rates (a performance bug)
d) correct locking order, dead locks, live locks
e) incomprehensible core dumps and stack traces
f) race conditions

To control 2 power supplies, run 2 frontend programs, 1 per power supply.

To control 64 frontend cards, run 1 frontend with many threads: 64 (per device) + 1 (main thread) + 1 (RPC handler) + 1 
(watchdog) + 1 (common event generator/data transmitter) + 1 (odb/web page status update). You *will* bump into each 
and every one of the problems (a) to (f) above.

K.O.
ELOG V3.1.4-2e1708b5