Frontend user code (object oriented - TMFE): Difference between revisions

From MidasWiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 9: Line 9:
* [[Equipment List Parameters]]
* [[Equipment List Parameters]]
* [[Equipment Flags]]
* [[Equipment Flags]]
* [[Event Notification (Hot-Link)]]
</div>
</div>


Line 22: Line 21:
* In the C-style framework you must link against <code>libmfe.a</code> and <code>libmidas.a</code>. In this framework you should only link against <code>libmidas.a</code>.
* In the C-style framework you must link against <code>libmfe.a</code> and <code>libmidas.a</code>. In this framework you should only link against <code>libmidas.a</code>.
* In the C-style framework you do not write a <code>main()</code> function - you just implement functions (and variables) that the framework uses. In this framework you write your own <code>main()</code> function (generally just 2 lines of code).
* In the C-style framework you do not write a <code>main()</code> function - you just implement functions (and variables) that the framework uses. In this framework you write your own <code>main()</code> function (generally just 2 lines of code).
* In the C-style framework you populate nested structs with important information like the equipment name and type. In this framework you set member variables of classes instead.
* In the C-style framework you populate nested structs with important information like the equipment name and type. In this framework you set member variables in classes instead.
* In the C-style framework you write one function per frontend that will get called at the start of each run. In this framework you write one such function for each equipment in your frontend.


= Examples =
= Examples =
Line 47: Line 47:
* <code>MVOdb</code> - simplified access to ODB that suits some use cases. You can still use the <code>db_*</code> family of [https://bitbucket.org/tmidas/midas/src/develop/include/midas.h C-style functions] or the <code>midas::odb</code> [[Odbxx|JSON-like interface]].
* <code>MVOdb</code> - simplified access to ODB that suits some use cases. You can still use the <code>db_*</code> family of [https://bitbucket.org/tmidas/midas/src/develop/include/midas.h C-style functions] or the <code>midas::odb</code> [[Odbxx|JSON-like interface]].


== Status - TMFEResult ==
More details about these classes follow below.


TMFeOk(), TMFeErrorMessage(), TMFeMidasError()
== Status - TMFEResult and TMFeOk ==
 
Most functions in the TMFE framework return their status via a <code>TMFEResult</code> object. For example, the interface for handling a begin-of-run transition is:
 
  TMFeResult HandleBeginRun(int run_number);
 
When you implement this in your class that derives from <code>TMFeEquipment</code>, you must construct and return a <code>TMFeResult</code> object. Ways to do this are:
 
# Use the plain TMFeResult constructor.
# TMFeResult(int code, const std::string& str);
# See $MIDASSYS/include/midas.h for details of pre-defined error codes (like FE_ERR_ODB is 602), but you may use any integer.
# Note that midas defines SUCCESS as 1!
return TMFeResult(FE_ERR_ODB, "Failed to read value from ODB");
 
# Use a shorthand to say that everything is okay.
return TMFeOk();
 
# Say there was a failure without specifying a specific midas status code (SUCCESS in midas is 1; this wrapper will set a code of 0)
return TMFeErrorMessage("Failed to read value from ODB");
 
# Apply some formatting to your error message saying which function had the issue.
# This example will result in a message of "Failed to read value from ODB, some_func() status 602"
return TMFeMidasError("Failed to read value from ODB", "some_func", FE_ERR_ODB);
 
Note that none of the above examples log the error message in the midas [[Message_System|message log]], they are simply used to provide more information about the error than just a status code. Call <code>TMFE::Msg()</code> (a wrapper around <code>cm_msg()</code>) if you want to log an error.


== Equipment - derive from TMFeEquipment ==
== Equipment - derive from TMFeEquipment ==

Revision as of 12:58, 21 April 2023


This page is a work in progress!


Links

Introduction

This page will document using object-oriented C++ to create a midas Frontend. For the classic C-style frontend see Frontend user code. For python frontends see Python.

Regardless of the framework you use, all midas frontends follow the same concept of "equipment" (which can be periodic or polled) that produce data in midas banks that can eventually get logged to file or the midas history system. If you don't need to produce data, you can write midas clients without using one of the frontend frameworks.

Key differences to the C-style frontend framework

  • In the C-style framework you must link against libmfe.a and libmidas.a. In this framework you should only link against libmidas.a.
  • In the C-style framework you do not write a main() function - you just implement functions (and variables) that the framework uses. In this framework you write your own main() function (generally just 2 lines of code).
  • In the C-style framework you populate nested structs with important information like the equipment name and type. In this framework you set member variables in classes instead.
  • In the C-style framework you write one function per frontend that will get called at the start of each run. In this framework you write one such function for each equipment in your frontend.

Examples

Examples of TMFE-based frontends can be found at

  • $MIDASSYS/progs/tmfe_example.cxx - minimal frontend with a periodic equipment
  • $MIDASSYS/progs/tmfe_example_frontend.cxx - the equivalent of $MIDASSYS/examples/experiment/frontend.cxx
  • $MIDASSYS/progs/tmfe_example_indexed.cxx - example of a frontend that handles the -i argument. If you pass -i 3 on the command line, the equipment will appear as example_03 and write data to BUF03
  • $MIDASSYS/progs/tmfe_example_multithread.cxx - example of a frontend that offloads some tasks to other threads. You can offload RPC communication (ODB updates, run transitions etc), periodic equipment checks, polled equipment checks into 3 separate threads if desired. The default is to run all checks in the main thread.
  • $MIDASSYS/progs/tmfe_example_everything.cxx - "kitchen sink" example that uses almost all features of the framework.
  • $MIDASSYS/progs/fetest.cxx - contains several periodic equipment and one that only reacts to RPC commands and never writes any data.

Frontend code

Major classes

The main base classes you will need to derive from are:

  • TMFrontend
  • TMFeEquipment

Other classes you will interact with are:

  • TMFE - wrapper of some midas functions (cm_msg()/fMfe->Msg(), cm_yield()/fMfe->Yield() etc) that also contains some global state (fRunNumber etc).
  • TMFeResult - used by the framework to report success/failure of commands (rather than raw integer status codes used in the C-style framework). Note that the framework does NOT use exceptions to report errors.
  • MVOdb - simplified access to ODB that suits some use cases. You can still use the db_* family of C-style functions or the midas::odb JSON-like interface.

More details about these classes follow below.

Status - TMFEResult and TMFeOk

Most functions in the TMFE framework return their status via a TMFEResult object. For example, the interface for handling a begin-of-run transition is:

  TMFeResult HandleBeginRun(int run_number);

When you implement this in your class that derives from TMFeEquipment, you must construct and return a TMFeResult object. Ways to do this are:

# Use the plain TMFeResult constructor. 
# TMFeResult(int code, const std::string& str);
# See $MIDASSYS/include/midas.h for details of pre-defined error codes (like FE_ERR_ODB is 602), but you may use any integer.
# Note that midas defines SUCCESS as 1!
return TMFeResult(FE_ERR_ODB, "Failed to read value from ODB");
# Use a shorthand to say that everything is okay.
return TMFeOk();
# Say there was a failure without specifying a specific midas status code (SUCCESS in midas is 1; this wrapper will set a code of 0)
return TMFeErrorMessage("Failed to read value from ODB");
# Apply some formatting to your error message saying which function had the issue.
# This example will result in a message of "Failed to read value from ODB, some_func() status 602"
return TMFeMidasError("Failed to read value from ODB", "some_func", FE_ERR_ODB);

Note that none of the above examples log the error message in the midas message log, they are simply used to provide more information about the error than just a status code. Call TMFE::Msg() (a wrapper around cm_msg()) if you want to log an error.

Equipment - derive from TMFeEquipment

Frontend - derive from TMFrontend

main()

 int main(int argc, char* argv[]) {
    MyFrontend fe;
    return fe.FeMain(argc, argv);
 }

TMFE singleton

MVOdb

Compilation