Back Midas Rome Roody Rootana
  Midas DAQ System, Page 114 of 138  Not logged in ELOG logo
New entries since:Wed Dec 31 16:00:00 1969
ID Date Author Topicup Subject
  1855   16 Mar 2020 Konstantin OlchanskiInfomhttpd mongoose 6.16 update
the update of mhttpd to mongoose version 6.16 was committed to the develop branch of midas. If you do not want to use this 
updated code or if it causes problems, please use the mhttpd6 executable or midas from the midas-2020-03 release branch.

new features:

- IPv6 support
- built-in http proxy
- fine grain locking - serving "resource" files (html, css, etc) and serving json-rpc requests no longer takes the global lock
- reduced number of DNS queries when checking host list access (DNS replies are cached)
- (I decided to not implement caching of password requests and dynamic reload of password file - it is too hard).

internal changes:

Recent versions of the mongoose web server library have removed all their internal multithreading,
leaving the library fully single-threaded. This resulted in major simplification of many things. An improvement.
(the civetweb fork of mongoose retains the old multithreading code, that model seems to work better
which used inside ROOT). As implemented in mhttpd, all network connections are handled by the main thread,
all midas http requests are handled by worker threads that are started on the as-needed basis.

The old mongoose 6.4 based mhttpd code survived almost without changes - as a compile-time
option - so now I build 2 mhttpd executables: mhttpd with the new code and mhttpd6 with the old code
so people have something to run in case the new code bombs.

http proxy:

Experiments that use private networks usually configure the apache httpd as a web proxy to allow
access from the outside to the web-controlled devices on the private network. Making changes
to this proxy requires root access, requires restarting httpd, etc. To make things simpler, mhttpd now
includes a web proxy (almost the complete implementation is provided by the mongoose library). Configuration
is done from ODB, restarting mhttpd is not needed.

improved multithreading:

Since most of the MIDAS library is now thread-safe, mhttpd no longer needs to take the "big midas lock"
to service most web requests. Access to files, access to ODB, etc is now fully threaded. Some parts
of MIDAS are not thread-safe, i.e. access to history and log files, so a flag was added to the mjsonrpc library
to mark which RPC methods are not thread-safe.

Note that despite these improvements, mhttpd still suffers from "http head-of-queue blocking"
https://en.wikipedia.org/wiki/Head-of-line_blocking
because (i.e. the google chrome web browser) tends to use just 1 TCP connection for all JSONRPC requests,
after a request for a history read (can take a long time), all subsequent requests for web page updates, etc
will have to wait until it completes, causing unresponsive user experience. (it looks as if mhttpd is single-threaded!).

A solution for this problem is HTTP/2, which is not yet implemented by mongoose and is not quite yet available
for apache httpd.

More later...
K.O.
  1856   16 Mar 2020 Konstantin OlchanskiInfomhttpd mongoose 6.16 update
> the update of mhttpd to mongoose version 6.16 was committed to the develop branch of midas.

The new code implements 3 http ports:

- localhost port 8080 - enabled by default - suitable for "I want to test midas on my laptop" and for connecting from the apache httpd
https password protected gateway.

- insecure http port 8081 - disabled by default - with optional password protection (HTTP Digest auth), and optional hostlist access
control - for the case when the https gateway is running on a different computer (i.e. ALPHA at CERN).

(My reading of "internet opinions" about HTTP Digest authentication over unencrypted HTTP is
that while considered very obsolete, there are no specific security problems and exploits
against it - other than the usual - man-in-the-middle and "steal the password file" attacks.
So while I do not recommend using it, I do not feel justified to remove/disable it on security grounds.
It provides an alternative password protection when use of SSL/HTTPS is too difficult).

- https port 8443 - disabled by default - also with optional password protection (HTTP Digest auth), and optional hostlist access
control. HTTP Digest password protection over HTTPS is deemed as secure at "HTTP Basic" password protection over HTTPS and
that is what is used by apache httpd password protection.

(The main problem with mhttpd support of HTTPS is obtaining an https certificate. Right now mhttpd
instructs the user to generate a self-signed certificate. But there is 2 problems: modern browsers dislike self-signed
certificates (even when explicitely marked "trust it!") and there is no check for certificate expiration.
I guess one could try to integrate mhttpd with certbot and the let's-encrypt system, but there
is problems, i.e. the certificate files live in readable-only-by-root directories, etc. I would rather
wait until mongoose implement certbot integration in their code).

More later...
K.O.
  1857   16 Mar 2020 Konstantin OlchanskiInfomhttpd mongoose 6.16 update
> > the update of mhttpd to mongoose version 6.16 was committed to the develop branch of midas.

Configuration is done by ODB /WebServer:

---------------------------------------------------------------------------
[local:javascript1:S]/WebServer>ls -l
Key name                        Type    #Val  Size  Last Opn Mode Value
---------------------------------------------------------------------------
mime.types                      DIR
Enable localhost port           BOOL    1     4     2h   0   RWD  y
localhost port                  INT     1     4     2h   0   RWD  8080
localhost port passwords        BOOL    1     4     2h   0   RWD  n
Enable insecure port            BOOL    1     4     12h  0   RWD  n
insecure port                   INT     1     4     2h   0   RWD  8081
insecure port passwords         BOOL    1     4     2h   0   RWD  y
insecure port host list         BOOL    1     4     2h   0   RWD  y
Enable https port               BOOL    1     4     12h  0   RWD  n
https port                      INT     1     4     2h   0   RWD  8443
https port passwords            BOOL    1     4     2h   0   RWD  y
https port host list            BOOL    1     4     2h   0   RWD  y
Host list                       STRING  10    32    2h   0   RWD
                                        [0]             localhost
                                        [1]
                                        [2]
                                        [3]
                                        [4]
                                        [5]
                                        [6]
                                        [7]
                                        [8]
                                        [9]
Enable IPv6                     BOOL    1     4     2h   0   RWD  y
Proxy                           DIR
---------------------------------------------------------------------------

Most entries are self-obvious, but note:

- mime.types contains the mapping of file extensions of file content-type telling browser what to do:

---------------------------------------------------------------------------
[local:javascript1:S]/WebServer>ls -l mime.types/
Key name                        Type    #Val  Size  Last Opn Mode Value
---------------------------------------------------------------------------
.HTML                           STRING  1     10    2h   0   RWD  text/html
.HTM                            STRING  1     10    2h   0   RWD  text/html
.CSS                            STRING  1     9     2h   0   RWD  text/css
---------------------------------------------------------------------------

- Proxy directory configures the http proxy (as implemented by mongoose, I am
not sure if I understand all limitations):

---------------------------------------------------------------------------
[local:javascript1:S]/WebServer>ls -l Proxy/
Key name                        Type    #Val  Size  Last Opn Mode Value
---------------------------------------------------------------------------
example                         STRING  1     27    17h  0   RWD  #http://localhost:8080
---------------------------------------------------------------------------

("#" means - commented-out)

http://localhost:8080/proxy/example/foo/bar/baz proxies to http://localhost:8080/foo/bar/baz

- "Enable IPv6" tells mhttpd to also listen on the IPv6 ports. The best I can tell IPv6 works on the Mac,
and with luck will get some testing at CERN where IPv6 is in use.

Documentation on the midas wiki still needs to be updated for this.
K.O.
  1858   17 Mar 2020 Konstantin OlchanskiInfombedtls, mhttpd mongoose 6.16 update
> > > the update of mhttpd to mongoose version 6.16 was committed to the develop branch of midas.

current code looks for the mbedtls library in ../mbedtls (next to midas)

if cmake misdetects it, turn it off by setting NO_MBEDTLS (same as NO_ROOT & co)

if you do want to build mhttpd with mbedtls, do this:

cd .../midas
cd ../
git clone https://github.com/ARMmbed/mbedtls.git
cd mbedtls
git submodule update --init ### this will populate the "crypto" directory
make ### if "python2" is missing, building of test suite programs will fail, but the libraries needed for midas will be built

cd ../midas
make cmake...

K.O.
  1870   30 Mar 2020 Stefan RittInfombedtls, mhttpd mongoose 6.16 update
I had some quick look at the new mongoose code and didn't find anything I dislike. Did a quick test of the proxy which worked and is nice to have. 
Agree with all KO said about authentication.

So if there are no complaints, I would suggest that we move the summary of this thread into the official documentation.

Stefan
  1871   03 Apr 2020 Stefan RittInfoChange of TID_xxx data types
We have to request of a 64-bit integer data type to be included in MIDAS banks.
Since 64-bit integers are on some systems "long" and on other systems "long long",
I decided to create the two new data types

TID_INT64
TID_UINT64

which follows more the standard C++ tradition:

https://en.cppreference.com/w/cpp/types/integer

To be consistent, I renamed the old types:

TID_BYTE       -> TID_UINT8
TID_SBYTE      -> TID_INT8
TID_WORD       -> TID_UINT16
TID_SHORT      -> TID_INT16
TID_DWORD      -> TID_UINT32
TID_INT        -> TID_INT32

I left the old definitions in midas.h, so old code will still compile fine and be binary
compatible. But if you write new code, the new types are recommended.

If you save the ODB in ASCII format, the new types are used as stings as well, like

[/Experiment]
ODB timeout = INT32 : 10000

but the old types are still understood when you load an old ODB file.

I hope I didn't break anything, please report if you have any issue.

Stefan
  1872   03 Apr 2020 Francesco RengaInfoCLOCK_REALTIME on MacOS
Dear all,
       I'm trying to compile MIDAS on MacOS 10.10 and I get this error:

/Users/francesco/MIDAS/midas/src/system.cxx:3187:18: error: use of undeclared identifier 
'CLOCK_REALTIME'
   clock_settime(CLOCK_REALTIME, &ltm);

Is it related to my (old) version of MacOS? Can I fix it somehow?

Thank you,
      Francesco
  1873   03 Apr 2020 Stefan RittInfoCLOCK_REALTIME on MacOS
> Dear all,
>        I'm trying to compile MIDAS on MacOS 10.10 and I get this error:
> 
> /Users/francesco/MIDAS/midas/src/system.cxx:3187:18: error: use of undeclared identifier 
> 'CLOCK_REALTIME'
>    clock_settime(CLOCK_REALTIME, &ltm);
> 
> Is it related to my (old) version of MacOS? Can I fix it somehow?
> 
> Thank you,
>       Francesco

If I see this correctly, you need at least MacOSX 10.12. If you can't upgrade, you can just remove line 3187 
from system.cxx. This function is only used in an online environment, where you would run a frontend on your 
Mac, which you probably don't do. So removing it does not hurt you.

Stefan
  1886   25 Apr 2020 Konstantin OlchanskiInfoCLOCK_REALTIME on MacOS
> > /Users/francesco/MIDAS/midas/src/system.cxx:3187:18: error: use of undeclared identifier 
> > 'CLOCK_REALTIME'
> >    clock_settime(CLOCK_REALTIME, &ltm);
> > 
> > Is it related to my (old) version of MacOS? Can I fix it somehow?

I think the "set clock" function is a holdover from embedded operating systems
that did not keep track of clock time, i.e. VxWorks, and similar. Here a midas program
will get the time from the mserver and set it on the local system. Poor man's ntp,
poor man's ntpd/chronyd.

We should check if this function is called by anything, and if nothing calls it, maybe remove it?

K.O.
  1887   25 Apr 2020 Konstantin OlchanskiInfonew mac!
I received my new 2020 mac book air, so between Stefan and myself, MacOS support for 
MIDAS is assured for 5 more years at the least. K.O.
  1890   26 Apr 2020 Stefan RittInfoCLOCK_REALTIME on MacOS
> > > /Users/francesco/MIDAS/midas/src/system.cxx:3187:18: error: use of undeclared identifier 
> > > 'CLOCK_REALTIME'
> > >    clock_settime(CLOCK_REALTIME, &ltm);
> > > 
> > > Is it related to my (old) version of MacOS? Can I fix it somehow?
> 
> I think the "set clock" function is a holdover from embedded operating systems
> that did not keep track of clock time, i.e. VxWorks, and similar. Here a midas program
> will get the time from the mserver and set it on the local system. Poor man's ntp,
> poor man's ntpd/chronyd.
> 
> We should check if this function is called by anything, and if nothing calls it, maybe remove it?
> 
> K.O.

It's called in mfe.cxx via cm_synchronize:

/* set time from server */
#ifdef OS_VXWORKS
   cm_synchronize(NULL);
#endif

This was for old VxWorks systems which had no ntp/crond. Was asked for by Pierre long time ago. I don't use it 
(have no VxWorks). We can either remove it completely, or remove just the MacOSX part and just exit the program 
if called with an error message "not implemented on this OS".

Stefan
  1906   12 May 2020 Stefan RittInfoNew ODB++ API
Since the beginning of the lockdown I have been working hard on a new object-oriented interface to the online database ODB. I have the code now in an initial state where it is ready for 
testing and commenting. The basic idea is that there is an object midas::odb, which represents a value or a sub-tree in the ODB. Reading, writing and watching is done through this 
object. To get started, the new API has to be included with

   #include <odbxx.hxx>

To create ODB values under a certain sub-directory, you can either create one key at a time like:

   midas::odb o;
   o.connect("/Test/Settings", true);   // this creates /Test/Settings
   o.set_auto_create(true);            // this turns on auto-creation
   o["Int32 Key"] = 1;                 // create all these keys with different types
   o["Double Key"] = 1.23;
   o["String Key"] = "Hello";

or you can create a whole sub-tree at once like:

  midas::odb o = {
    {"Int32 Key", 1},
    {"Double Key", 1.23},
    {"String Key", "Hello"},
    {"Subdir", {
      {"Another value", 1.2f}
    }
  };
  o.connect("/Test/Settings");

To read and write to the ODB, just read and write to the odb object

   int i = o["Int32 Key];
   o["Int32 Key"] = 42;
   std::cout << o << std::endl;

This works with basic types, strings, std::array and std::vector. Each read access to this object triggers an underlying read from the ODB, and each write access triggers a write to the 
ODB. To watch a value for change in the odb (the old db_watch() function), you can use now c++ lambdas like:

   o.watch([](midas::odb &o) {
      std::cout << "Value of key \"" + o.get_full_path() + "\" changed to " << o << std::endl;
   });

Attached is a full running example, which is now also part of the midas repository. I have tested most things, but would not yet use it in a production environment. Not 100% sure if there 
are any memory leaks. If someone could valgrind the test program, I would appreciate (currently does not work on my Mac).

Have fun!

Stefan

  
Attachment 1: odbxx_test.cxx
/********************************************************************\

  Name:         odbxx_test.cxx
  Created by:   Stefan Ritt

  Contents:     Test and Demo of Object oriented interface to ODB

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

#include <string>
#include <iostream>
#include <array>
#include <functional>

#include "odbxx.hxx"
#include "midas.h"

/*------------------------------------------------------------------*/

int main() {

   cm_connect_experiment(NULL, NULL, "test", NULL);
   midas::odb::set_debug(true);

   // create ODB structure...
   midas::odb o = {
           {"Int32 Key", 42},
           {"Bool Key", true},
           {"Subdir", {
              {"Int32 key", 123 },
              {"Double Key", 1.2},
              {"Subsub", {
                 {"Float key", 1.2f},     // floats must be explicitly specified
                 {"String Key", "Hello"},
              }}
           }},
           {"Int Array", {1, 2, 3}},
           {"Double Array", {1.2, 2.3, 3.4}},
           {"String Array", {"Hello1", "Hello2", "Hello3"}},
           {"Large Array", std::array<int, 10>{} },   // array with explicit size
           {"Large String", std::string(63, '\0') },  // string with explicit size
   };

   // ...and push it to ODB. If keys are present in the
   // ODB, their value is kept. If not, the default values
   // from above are copied to the ODB
   o.connect("/Test/Settings", true);

   // alternatively, a structure can be created from an existing ODB subtree
   midas::odb o2("/Test/Settings/Subdir");
   std::cout << o2 << std::endl;

   // retrieve, set, and change ODB value
   int i = o["Int32 Key"];
   o["Int32 Key"] = i+1;
   o["Int32 Key"]++;
   o["Int32 Key"] *= 1.3;
   std::cout << "Should be 57: " << o["Int32 Key"] << std::endl;

   // test with bool
   o["Bool Key"] = !o["Bool Key"];

   // test with std::string
   std::string s = o["Subdir"]["Subsub"]["String Key"];
   s += " world!";
   o["Subdir"]["Subsub"]["String Key"] = s;

   // test with a vector
   std::vector<int> v = o["Int Array"];
   v[1] = 10;
   o["Int Array"] = v;        // assign vector to ODB object
   o["Int Array"][1] = 2;     // modify ODB object directly
   i = o["Int Array"][1];     // read from ODB object
   o["Int Array"].resize(5);  // resize array
   o["Int Array"]++;          // increment all values of array

   // test with a string vector
   std::vector<std::string> sv;
   sv = o["String Array"];
   sv[1] = "New String";
   o["String Array"] = sv;
   o["String Array"][2] = "Another String";

   // iterate over array
   int sum = 0;
   for (int e : o["Int Array"])
      sum += e;
   std::cout << "Sum should be 11: " << sum << std::endl;

   // creat key from other key
   midas::odb oi(o["Int32 Key"]);
   oi = 123;

   // test auto refresh
   std::cout << oi << std::endl;    // each read access reads value from ODB
   oi.set_auto_refresh_read(false); // turn off auto refresh
   std::cout << oi << std::endl;    // this does not read value from ODB
   oi.read();                       // this does manual read
   std::cout << oi << std::endl;

   midas::odb ox("/Test/Settings/OTF");
   ox.delete_key();

   // create ODB entries on-the-fly
   midas::odb ot;
   ot.connect("/Test/Settings/OTF", true);   // this forces /Test/OTF to be created if not already there
   ot.set_auto_create(true);        // this turns on auto-creation
   ot["Int32 Key"] = 1;             // create all these keys with different types
   ot["Double Key"] = 1.23;
   ot["String Key"] = "Hello";
   ot["Int Array"] = std::array<int, 10>{};
   ot["Subdir"]["Int32 Key"] = 42;
   ot["String Array"] = std::vector<std::string>{"S1", "S2", "S3"};
   std::cout << ot << std::endl;

   o.read();                        // re-read the underlying ODB tree which got changed by above OTF code
   std::cout << o.print() << std::endl;

   // iterate over sub-keys
   for (auto& oit : o)
      std::cout << oit.get_odb()->get_name() << std::endl;

   // print whole sub-tree
   std::cout << o.print() << std::endl;

   // dump whole subtree
   std::cout << o.dump() << std::endl;

   // delete test key from ODB
   o.delete_key();

   // watch ODB key for any change with lambda function
   midas::odb ow("/Experiment");
   ow.watch([](midas::odb &o) {
      std::cout << "Value of key \"" + o.get_full_path() + "\" changed to " << o << std::endl;
   });

   do {
      int status = cm_yield(100);
      if (status == SS_ABORT || status == RPC_SHUTDOWN)
         break;
   } while (!ss_kbhit());

   cm_disconnect_experiment();
   return 1;
}
  1913   20 May 2020 Konstantin OlchanskiInfoNew ODB++ API
>    midas::odb o;
>    o["foo"] = 1;

This is an excellent development.

ODB is a tree-structured database, JSON is a tree-structured data format,
and they seem to fit together like hand and glove. For programming
web pages, Javascript and JSON-style access to ODB seems to work really well.

And now with modern C++ we can have a similar API for working with ODB tree data,
as if it were Javascript JSON tree data.

Let's see how well it works in practice!

K.O.
  1914   20 May 2020 Stefan RittInfoNew ODB++ API
In meanwhile, there have been minor changes and improvements to the API:

Previously, we had:

>    midas::odb o;
>    o.connect("/Test/Settings", true);   // this creates /Test/Settings
>    o.set_auto_create(true);            // this turns on auto-creation
>    o["Int32 Key"] = 1;                 // create all these keys with different types
>    o["Double Key"] = 1.23;
>    o["String Key"] = "Hello";

Now, we only need:

      o.connect("/Test/Settings");
      o["Int32 Key"] = 1;                 // create all these keys with different types
      ...

no "true" needed any more. If the ODB tree does not exist, it gets created. Similarly, set_auto_create() can be dropped, it's on by default (thought this makes more sense). Also the iteration over subkeys has 
been changed slightly.

The full example attached has been updated accordingly. 

Best,
Stefan
Attachment 1: odbxx_test.cxx
/********************************************************************\

  Name:         odbxx_test.cxx
  Created by:   Stefan Ritt

  Contents:     Test and Demo of Object oriented interface to ODB

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

#include <string>
#include <iostream>
#include <array>
#include <functional>

#include "midas.h"
#include "odbxx.hxx"

/*------------------------------------------------------------------*/

int main() {

   cm_connect_experiment(NULL, NULL, "test", NULL);
   midas::odb::set_debug(true);

   // create ODB structure...
   midas::odb o = {
      {"Int32 Key", 42},
      {"Bool Key", true},
      {"Subdir", {
         {"Int32 key", 123 },
         {"Double Key", 1.2},
         {"Subsub", {
            {"Float key", 1.2f},     // floats must be explicitly specified
            {"String Key", "Hello"},
         }}
      }},
      {"Int Array", {1, 2, 3}},
      {"Double Array", {1.2, 2.3, 3.4}},
      {"String Array", {"Hello1", "Hello2", "Hello3"}},
      {"Large Array", std::array<int, 10>{} },   // array with explicit size
      {"Large String", std::string(63, '\0') },  // string with explicit size
   };

   // ...and push it to ODB. If keys are present in the
   // ODB, their value is kept. If not, the default values
   // from above are copied to the ODB
   o.connect("/Test/Settings");

   // alternatively, a structure can be created from an existing ODB subtree
   midas::odb o2("/Test/Settings/Subdir");
   std::cout << o2 << std::endl;

   // set, retrieve, and change ODB value
   o["Int32 Key"] = 42;
   int i = o["Int32 Key"];
   o["Int32 Key"] = i+1;
   o["Int32 Key"]++;
   o["Int32 Key"] *= 1.3;
   std::cout << "Should be 57: " << o["Int32 Key"] << std::endl;

   // test with bool
   o["Bool Key"] = false;
   o["Bool Key"] = !o["Bool Key"];

   // test with std::string
   o["Subdir"]["Subsub"]["String Key"] = "Hello";
   std::string s = o["Subdir"]["Subsub"]["String Key"];
   s += " world!";
   o["Subdir"]["Subsub"]["String Key"] = s;

   // test with a vector
   std::vector<int> v = o["Int Array"]; // read vector
   std::fill(v.begin(), v.end(), 10);
   o["Int Array"] = v;        // assign vector to ODB array
   o["Int Array"][1] = 2;     // modify array element
   i = o["Int Array"][1];     // read from array element
   o["Int Array"].resize(5);  // resize array
   o["Int Array"]++;          // increment all values of array

   // test with a string vector
   std::vector<std::string> sv;
   sv = o["String Array"];
   sv[1] = "New String";
   o["String Array"] = sv;
   o["String Array"][2] = "Another String";

   // iterate over array
   int sum = 0;
   for (int e : o["Int Array"])
      sum += e;
   std::cout << "Sum should be 47: " << sum << std::endl;

   // creat key from other key
   midas::odb oi(o["Int32 Key"]);
   oi = 123;

   // test auto refresh
   std::cout << oi << std::endl;    // each read access reads value from ODB
   oi.set_auto_refresh_read(false); // turn off auto refresh
   std::cout << oi << std::endl;    // this does not read value from ODB
   oi.read();                       // this forces a manual read
   std::cout << oi << std::endl;

   // create ODB entries on-the-fly
   midas::odb ot;
   ot.connect("/Test/Settings/OTF");// this forces /Test/OTF to be created if not already there
   ot["Int32 Key"] = 1;             // create all these keys with different types
   ot["Double Key"] = 1.23;
   ot["String Key"] = "Hello";
   ot["Int Array"] = std::array<int, 10>{};
   ot["Subdir"]["Int32 Key"] = 42;
   ot["String Array"] = std::vector<std::string>{"S1", "S2", "S3"};
   std::cout << ot << std::endl;

   o.read();                        // re-read the underlying ODB tree which got changed by above OTF code
   std::cout << o.print() << std::endl;

   // iterate over sub-keys
   for (midas::odb& oit : o)
      std::cout << oit.get_name() << std::endl;

   // print whole sub-tree
   std::cout << o.print() << std::endl;

   // dump whole subtree
   std::cout << o.dump() << std::endl;

   // delete test key from ODB
   o.delete_key();

   // watch ODB key for any change with lambda function
   midas::odb ow("/Experiment");
   ow.watch([](midas::odb &o) {
      std::cout << "Value of key \"" + o.get_full_path() + "\" changed to " << o << std::endl;
   });

   do {
      int status = cm_yield(100);
      if (status == SS_ABORT || status == RPC_SHUTDOWN)
         break;
   } while (!ss_kbhit());

   cm_disconnect_experiment();
   return 1;
}
  1915   20 May 2020 Pintaudi GiorgioInfoNew ODB++ API
All this is very good news. I really wish this were available some months ago: it would have helped me immensely. The old C API was clunky at best.
I really like the idea and looking forward to using it (even if at the moment I do not have the need to) ...
  1916   20 May 2020 Konstantin OlchanskiInfoNew ODB++ API
> All this is very good news. I really wish this were available some months ago: it would have helped me immensely. The old C API was clunky at best.
> I really like the idea and looking forward to using it (even if at the moment I do not have the need to) ...

Yes, I have designed new C-style MIDAS ODB APIs twice now (VirtualOdb in ROOTANA and MVOdb in ROOTANA and MIDAS),
and I was never happy with the results. There is too many corner cases and odd behaviour. Let's see how
this C++ interface shakes out.

For use in analyzers, Stefan's C++ interface still need to be virtualized - right now it has only one implementation
with the MIDAS ODB backend. In analyzers, we need XML, JSON (and a NULL ODB) backends. The API looks
to be clean enough to add this, but I have not looked at the implementation yet. So "watch this space" as they say.

K.O.
  1941   09 Jun 2020 Isaac Labrie BoulayInfoPreparing the VME hardware - VME address jumpers.
Hey folks,

I'm currently working on setting up a MIDAS experiment and I am following the 
"Setup MIDAS experiment at Triumf" page on 
MidasWiki(https://midas.triumf.ca/MidasWiki/index.php/Setup_MIDAS_experiment_at_
TRIUMF).

The 3rd line of the hardware checklist under the "Prepare VME hardware section" 
has a link to a page that doesn't exit anymore, I'm trying to figure out how to 
setup the VME address jumpers on the VME modules.

Does anyone know how to setup the VME modules? Or, can anyone send me a link to 
instructions?

Thanks a lot for your time.

Isaac
Attachment 1: VME_address_jumpers_broken_link.PNG
VME_address_jumpers_broken_link.PNG
  1943   10 Jun 2020 Konstantin OlchanskiInfoPreparing the VME hardware - VME address jumpers.
Hi, if you are not using any VME hardware, then you have no VME address jumpers to 
set. https://en.wikipedia.org/wiki/VMEbus

K.O.
  1947   12 Jun 2020 Isaac Labrie BoulayInfoPreparing the VME hardware - VME address jumpers.
> Hi, if you are not using any VME hardware, then you have no VME address jumpers to 
> set. https://en.wikipedia.org/wiki/VMEbus
> 
> K.O.

Hi thanks for taking the time to help me out. I am using a VME-MWS in this experiment.

Let me know what you think.

Isaac
  1955   19 Jun 2020 Isaac Labrie-BoulayInfoBuilding/running a Frontend Task
To build a frontend task, the user code and system code are compiled and linked 
together with the required libraries, by running a Makefile (e.g. 
../midas/examples/experiment/Makefile in the MIDAS package).

I tried building the CAMAC example frontend and I get this error:

g++: error: /home/rcmp/packages/midas/drivers/camac/ces8210.c: No such file or 
directory
g++: error: /home/rcmp/packages/midas/linux/lib/libmidas.a: No such file or 
directory
make: *** [camac_init.exe] Error 1

Obviously, I'm running the "make all" command from the camac directory. Why 
would I get this "no such file" error? Do I need to download the MIDAS packages 
inside my experiment directory?

Thanks for helping me out.

Isaac
ELOG V3.1.4-2e1708b5