[programmer/prog-manager.tex] \section{Introduction} %this chapter covers the manager API description \index{Core classes !dabc::Manager} The \class{dabc::Manager} is the central singleton object of the \dabc~ framework. It combines a number of different roles, such as: \bcir \item objects manager; \item memory pools manager; \item threads manager; \item commands dispatcher; \item run control state manager; \item plug-in manager for factories and application; \item implementation of control and configuration system \ecir Although these functionalities internally could as well be treated in separate classes, \class{dabc::Manager} class defines the common application programmer's interface to access most of these features. Since the manager is a singleton, these methods are available everywhere in the user code by means of the static handle \func{dabc::mgr()->}. The following section \ref{prog_manager_framework} describes such interface methods to be used by the programmer of the \class{Module}, \class{Transport}, \class{Device}, and \class{Application} classes. In contrast to this, section \ref{prog_manager_controls} gives a guide how to re-implement the \class{Manager} class itself for a different control and configuration system. This should be seldomly necessary for the common DAQ designer, but is added here as a reference and as useful insight into the \dabc~ mechanisms. \section{Framework interface} \label{prog_manager_framework} %here description of mostly used methods to be called from application, modules, etc. \subsection{General object management} \label{prog_manager_framework_objects} All objects are organized in a folder structure and can be accessed by the full path name. However, for most purposes it is recommended to rather use higher level \class{Manager} methods to cause some action(e.~g.~ \func{StartModule()}) than to work directly with the primitive objects. \begin{description} \item[\em Module* FindModule\small (const char* name)] : Access to a \class{Module} by name. Returns $0$ if module does not exist. \item[\em Port* FindPort\small (const char* name)]: Access to a \class{Port} by name. Returns $0$ if port does not exist. \item[\em Device* FindDevice\small (const char* name)] : Access to a \class{Device} by name. Returns $0$ if device does not exist. \item[\em WorkingThread* FindThread\small (const char* name, const char* required\_class = 0)] : Access to a \class{WorkingThread} by name. The \func{required\_class} string may be specified to check if the working thread implementation matches the client intentions. Returns $0$ if thread object does not exist, or if it does not fullfill \func{required\_class}. \item[\em Application* GetApp()] : Access to the unique \class{Application} Object of this node. \end{description} \subsection{Factory methods} Since all \dabc~ objects are provided by \class{dabc::Factory} plug-ins, the application programmer needs to invoke corresponding factory methods to instantiate them. However, the factories themselves should not be accessed by the user code (although the \class{Manager} offers a getter method, see section \ref{prog_manager_framework_objects}). Instead, creation and registration of the key objects, like \class{Module} or \class{Device}, is done transparently by the \class{Manager} within specific creation methods. These will scan over all existing factories whether the corresponding factory method can provide an object of the requested class name. In this case the object is created, kept in the object manager, and may be addressed by its full name later. \begin{description} \item[\em bool CreateModule\small (const char* classname, const char* modulename, const char* thrdname = 0)] : \index{Manager interface !CreateModule()} Instantiate a \class{Module} of class \func{classname} with the object name \func{modulename}. Optionally, the name of the working thread \func{thrdname} may be specified that shall run this module. If a thread of this name is already exisiting, it will be also applied for the new module; otherwise, a new thread of the name will be created. If \func{thrdname} is not defined, \dabc~ will use module name for it. Returns \keyw{true} or \keyw{false} depending on the instantiation success. \item[\em bool CreateDevice\small (const char* classname, const char* devname)]: \index{Manager interface !CreateDevice()} Instantiate a \class{Device} of class \func{classname} with the object name \func{devname}. Returns \keyw{true} or \keyw{false} depending on the instantiation success. % \item[\em ThreadRef CreateThread(const std::string& thrdname, const std::string& classname = 0, const std::string& devname = "", Command cmd = 0)] : \item[\em bool CreateTransport\small (const char* portname, const char* transportkind, const char* thrdname = 0)] : \index{Manager interface !CreateTransport()} Instantiate a \class{Transport} of the specified kind \func{transportkind} (e.~g.~ "mbs::ServerTransport") and connect it to the port of full name \func{portname} (e.~g.~ "Readout/Input1"). Kind can specify device name, which than create appropriate transport instance. Optionally the name of the working thread \func{thrdname} may be specified that shall run this transport. If a thread of this name is already exisiting, it will be also applied for the new transport; otherwise, a new thread of the name will be created. If \func{thrdname} is not defined, \dabc~ will use a new thread automatically with an internal name. Returns \keyw{true} or \keyw{false} depending on the instantiation success. \item[\em bool CreateApplication\small (const std::string& classname = "", const std::string& appthrd = "")] : \index{Manager interface !CreateApplication()} Instantiate the \class{Application} of class \func{classname}. Optionally the name \func{appthrd} of the main application thread may be specified. Used in the \func{main()} function of the \dabc~ runtime executable on inititialization time. \end{description} \subsection{Module manipulation} \begin{description} \item[\em void StartModule\small (const char* modulename)] : \index{Manager interface !StartModule()} Enables the module of name \func{modulename} for processing. Depending on the \class{Module} type (synchronous or asynchronous, see section \ref{prog_overview_modules}), this will start execution of the \func{MainLoop()}, or activate processing of the queued events belonging to this module, resp. \item[\em void StopModule\small (const char* modulename)] : \index{Manager interface !StopModule()} Disables processing for the module of name \func{modulename}. \item[\em bool StartAllModules\small ()] : \index{Manager interface !StartAllModules()} Enables processing for all modules with apllication identifier number \func{appid}. The optional identifier may be set in the \func{Module} definition to select different kinds of modules here. By default, this method will start all exisiting modules on this node. Returns \keyw{true} of \keyw{false} depending on success. \item[\em bool StopAllModules\small ()] : \index{Manager interface !StopAllModules()} Disables processing for all modules with application identifier number \func{appid}. The optional identifier may be set in the \func{Module} definition to select different kinds of modules here. By default, this method will stop all exisiting modules on this node. Returns \keyw{true} of \keyw{false} depending on success. \item[\em bool DeleteModule\small (const char* modulename)] : \index{Manager interface !DeleteModule()} Deletes the module of name \func{modulename}. Returns \keyw{true} of \keyw{false} depending on the deletion success. \item[\em bool IsModuleRunning\small (const char* modulename)] : \index{Manager interface !IsModuleRunning()} Depricated. Use FindModule(modulename).IsRunning() method instead. Method returns \keyw{true} if module of name \func{modulename} is running, i.~e.~ its processing is enabled. If module does not exist or is not active, \keyw{false} is returned. \item[\em bool IsAnyModuleRunning()] : \index{Manager interface !IsAnyModuleRunning()} Method returns \keyw{false} if \strong{no} exisiting module is running anymore. Otherwise returns \keyw{true}. \item[\em bool ConnectPorts\small (const char* port1name, const char* port2name, const char* devname=0)] : \index{Manager interface !ConnectPorts()} \\ Connects module \class{Port} of full name \func{port1name} with another module \class{Port} of full name \func{port2name}. A full port name consists of the module name and a local port name, separated by forward slash, e.~g.~ "Readout3/Output", "CombinerModule/Input2". Optionally the \class{Device} name for the connection may be defined with argument \func{devname}. By default, the ports are connected with a FIFO-like transport of queued \class{Buffer} references in local memory. \end{description} \subsection{Thread management} \begin{description} \end{description} \subsection{Command submission} \label{prog_manager_framework_commands} \begin{description} \item[\em bool Submit\small (Command cmd)] : \index{Manager interface !Submit()} This method generally submits a command \func{cmd} for execution. The command is put in the queue of its command receiver working thread and is then asynchronously executed there. The \class{Manager} will either forward the command to its receiver, if such is specified as command parameter; or the \class{Manager} working thread itself will execute the command. Thus method does not block and returns \keyw{true} if it accepts the command for execution, otherwise \keyw{false}. Manager commands queue can also be used to submit command not only direct for manager, but also for any other object on local or remote node. For that one from several following functions \func{SetCmdReceiver} should be used. \item[\em Command& SetReceiver\small (const char* itemname)] : \item[\em Command& SetReceiver\small (Object* rcv)] : \item[\em Command& SetReceiver\small (int nodeid, const char* itemname)] : \index{Command interface !SetReceiver()} Set receiver attribute of command \func{cmd}. The \func{itemname} is item name of the local node like "Module1". One can also specify \func{nodename} or \func{nodeid} of the node, to which command should be submitted. Returns pointer on the command itself. One can use \func{SetCmdReceiver} to submit command like: \begin{small} \begin{verbatim} dabc::mgr()->Submit(cmd.SetReceiver("Module1")); dabc::mgr()->Submit(cmd.SetReceiver(1, "Module1")); \end{verbatim} \end{small} \end{description} \subsection{Memory pool management} \begin{description} \item[\em bool CreateMemoryPool] {\small \bf\em (} \\ {\small \bf\em const char* poolname, unsigned buffersize, unsigned numbuffers, \\ unsigned numincrement, unsigned headersize, unsigned numsegments)} : \index{Manager interface !CreateMemoryPool()} Instantiates a \class{dabc::MemoryPool} of name \func{poolname}, with \func{numbuffers} buffers of size \func{buffersize}. If a pool of this name already exists, it will be extended. The \func{numincrement} value specifies with how many buffers at once the memory pool can optionally be extended on the fly. Optional arguments \func{headersize} and \func{numsegments} may define the buffer header size, and the partition of the buffer segments, resp. The \class{MemoryPool} mechanisms are discussed in detail in section \ref{prog_services_memory}. Method returns true or false depending on success. \item[\em Reference FindPool\small (const char* name)] : \index{Manager interface !FindPool()} Access to memory pool by name \func{name}. Returns empty reference if not found. \item[\em bool DeletePool\small (const char* name)] : \index{Manager interface !DeletePool()} Delete memory pool of name \func{name}. Returns true or false depending on success. \end{description} \subsection{Miscellaneous methods} \begin{description} \item[\em bool CleanupManager\small () ] : \index{Manager interface !CleanupApplication()} Safely deletes all modules, memory pools and devices created for user application. In the end all unused threads are also destroyed. \item[\em virtual void DestroyObject\small (Object* obj)] : \index{Manager interface !DestroyObject()} Deletes the referenced object \func{obj} in manager thread. Useful as safe replacement for call "delete this". \item[\em void Print()] : \index{Manager interface !Print()} Displays list of running threads and modules on \keyw{stdout}. \end{description} \section{Control system plug-in} \label{prog_manager_controls} For the common \dabc~ usage, the provided standard control and configuration system, featuring DIM protocol \cite{DIM}, XML setup files, and a generic Java GUI, will probably be sufficient. However, if e.~g.~ an experiment control system is already existing and the data acquisition shall be handled with the same means, it might be necessary to adjust \dabc~ to another controls and configuration framework. Moreover, future developments may replace the current standard control system by a more powerful, or a more convenient one. Because of this, the connection between the \dabc~ core system and the control system implementation was designed with a clear plug-in interface. Again the \class{dabc::Manager} class plays here a key role. This section covers all methods and mechanisms for the control system plug-in. As an example, part \ref{prog_manager_controls_DIM} describes in detail the standard implementation as delivered with the \dabc~ distribution . \subsection{Factory} \label{prog_manager_controls_factory} A new control system plug-in is added into \dabc~ by means of a \class{dabc::Factory} subclass that defines the method \func{bool CreateManagerInstance(const char* kind, dabc::Configuration* cfg)}. This method should create the appropriate \class{dabc::Manager} instance and return \keyw{true} if the name \func{kind}, as specified by the runtime environment, matches the implementation. The default \dabc~ runtime executable will also pass a configuration object \func{cfg} read from an XML file which may be passed to the constructor of the \class{Manager}. As it's mandatory for other \dabc~ factories, the \class{dabc::Factory} for the manager must be instantiated as global object in the code that implements it. This assures that the factory exists in the system on loading the corresponding library. \subsection{Manager} \label{prog_manager_controls_manager} Besides its role as a central singleton to access framework functionalities, the \class{dabc::Manager} is also the interface base class for the control and configuration system that is applied with \dabc~. \subsubsection{Virtual methods} The \class{dabc::Manager} defines several virtual methods concerning the {\em finite state machine}, the registration and subscription of parameters, the command communication in-between nodes, and the management of a DAQ cluster, resp. These methods have to be implemented for differrent kinds of control systems in an appropriate subclass and are described as follows: %\begin{compactdesc} \begin{description} \item[\em Manager(const char* managername, bool usecurrentprocess, Configuration* cfg)] : The constructor of the subclass. The recommended parameters are passed from the manager factory (see section \ref{prog_manager_controls_factory}) to the baseclass constructor, such as the object name of the manager; optionally a flag indicating to use either the main process or another thread for manager command execution; and an optional configuration object \func{cfg}. \item[\em\~{~}Manager()] : The destructor of the subclass. It should cleanup and remove the control system implementation. \item[\em bool Subscribe(dabc::Parameter* par, int remnode, const char* remname)] : \index{Manager interface !Subscribe()} This method shall link the value of a local parameter \func{par} to a remote parameter of name \func{remname} that exists on node number \func{remnode} of the DAQ cluster. Control system implementation may use a publisher-subscriber mechanism here to update the local subscription whenever the remote parameter changes its value. The actual update handler must call method \func{InvokeChange(const char* val)} of the local \func {dabc::Parameter* par} then. The new value \func{val} is passed to the parameter which will change itself appropriately. This decouples the parameter change from the invoking control system callback in a thread-safe manner. \item[\em bool Unsubscribe(dabc::Parameter* par)] : \index{Manager interface !Unsubscribe()} The subscription of a local parameter \func{par} to a remote paramter by a formerly called \func{Subscribe()} is removed from the control system. \item[\em int NumNodes()] : \index{Manager interface !NumNodes()} Returns the number of all nodes in the cluster. This value taken from a configuration database, e.~g.~ an XML file. \item[\em int NodeId() const] : \index{Manager interface !NodeId()} Returns the sequence id number of this node in the DAQ cluster. This should be taken from the cluster configuration. \item[\em bool IsNodeActive(int num)] : \index{Manager interface !IsNodeActive()} Returns \keyw{true} if DAQ cluster node of id number \func{num} is currently active, otherwise \keyw{false}. This may allow to check on runtime if some of the configured nodes are not available and should be excluded from the DAQ setup. \item[\em int ExecuteCommand(dabc::Command cmd)] : \index{Manager interface !ExecuteCommand()} This method executes synchronously any \dabc~ command that is submitted to this manager itself. It will run in the scope of the manager thread (depending on constructor argument \func{usecurrentprocess}, this is either the main process thread, or a dedicated manager thread). It may be re-implemented to add new commands required for the controls implementation. The \dabc~ mechanism of methods \func{SubmitCommand()} and \func{ExecuteCommand()} may allow to decouple control system callbacks from their execution thread. \end{description} %\end{compactdesc} \subsubsection{Baseclass methods} \label{prog_manager_controls_base} In addition to the virtual methods to be implemented in the manager subclass, there is a number of \class{dabc::Manager} base class methods that should be called from the control system to perform actions of the framework: \begin{description} \item[\em bool DoStateTransition(const char* state\_transition\_cmd)] : \index{Manager interface !DoStateTransition()} Performs the state machine transition of name \func{state\_transition\_cmd}. This method is synchronous and returns no sooner than the transition actions are completed (\keyw{true}) or an error is detected (\keyw{false}). Note that the real transition actions are still user defined in methods of the \class{dabc::Application} implementation. \item[\em bool IsTransitionAllowed(const char* state\_transition\_cmd, bool errout)] : \index{Manager interface !IsTransitionAllowed()} Checks if state transition of name \func{state\_transition\_cmd} is allowed for the default state machine implementation (which should be reproduced exactly by any external SM implementation) and returns \keyw{true} or \keyw{false}, resp. Argument \func{errout} may specify if error messages shall be printed to {\tt stdout}. \item[\em void RecvOverCommandChannel(const char* cmddata)] : \index{Manager interface !RecvOverCommandChannel()} Receives a \dabc~ command as text stream \func{cmddata} from a remote node. Usually this function should be called in a receiving callback of the control system communication layer, passing the received command representation to the core system. Here the command object is unstreamed again, forwarded to its receiver and executed. This is the pendant to virtual method \func{SendOverCommandChannel()} which should implement the \strong{sending} of a streamed command from the core to a remote manager by transport mechanisms of the control system. \end{description} \subsection{Implementation for DIM} \label{prog_manager_controls_DIM} The \dabc~ provides controls module, based on the DIM library \cite{DIM} and is marked by namespace \class{dimc::} (for "DIM Control"). % It features the DIM publisher-subscriber mechanism with \dabc~ process records and uses state machine module and XML parser as provided by the \dabc~core system. The main classes are described in the following: \subsubsection{\class{dimc::Observer}} \label{prog_manager_controls_DIM_observer} \index{DIM Control classes ! dimc::Observer} Implements the control system interface of \class{dabc::Worker} as described above. \begin{compactenum} \item It uses the \strong{state machine} of the \dabc~ core system. \item It exports a dedicated \class{dabc::StatusParameter} that is synchronized with the value of the state machine in \func{ParameterEvent()}. This parameter is required to display the state of the node on the generic Java GUI. \item It applies the generic \class{dabc::Configuration} for setting up the node properties. The standard executable \decl{dabc\_run} will create this object from parsing an XML file. \item The other interface functionalities use one component of class \class{dimc::Registry}. \end{compactenum} \subsubsection{\class{dimc::Registry}} \label{prog_manager_controls_DIM_registry} \index{DIM Control classes ! dimc::Registry} The main component of the \class{dimc::Manager} that offers service methods really implementing the manager interface. It registers all parameters, commands, and subscriptions; and it defines the allowed access methods for the DIM server itself. \begin{compactenum} \item The \strong{DIM server} is instantiated in the constructor as \class{dimc:Server} singleton. Methods \func{StartDIMServer()} and \func{StopDIMServer()} actually initiate and terminate the service. \item \strong{Naming of nodes and services:} Method \func{GetNodeName(int num)} of \class{dimc::Manager} uses \func{CreateDIMPrefix(num)} of \class{dimc::Registry}. This evaluates the unique name for node number \func{num} from the \class{dabc::Configuration} object: It consists of a global prefix ("DABC"), the configuration \func{NodeName()}, and the \func{ContextName()} property of the node id, all separated by forward slashes ("/"). The node name is also taken as prefix for the helper methods \func{BuildDIMName()} (\func{ReduceDIMName()}, resp.) that transform local \dabc~ parameter and command names into unique DIM names (and back, resp.). Moreover, methods \func{CreateFullParameterName()} (\func{ParseFullParameterName()}, resp.) define how the local parameter name itself is composed (decomposed, resp.) from the names of its parent module and its internal variable name. They utilize corresponding static methods of class \class{dimc::nameParser} in a thread-safe way. \item \strong{Parameter export:} \func{dimc::Manager::ParameterEvent()} uses methods \func{RegisterParameter()} (and \func{UnregisterParameter()}, resp.) to declare (undeclare, resp.) a corresponding DIM service. Here the \class{dimc::Registry} keeps auxiliary objects of class \class{dimc::ServiceEntry} that link the \class{DimService} with the \class{dabc::Parameter} (see section \ref{prog_manager_controls_DIM_servicentry}). On parameter change, method \func{ParameterUpdated()} will initiate an update of the corresponding DIM service. \item \strong{Control system commands:} Method \func{DefineDIMCommand(const char* name)} creates and registers simple (char array) \class{DimCommand} objects that may be executed on this node. The \class{dimc::Registry} constructor defines commands for all state machine transitions, such as Configure, Enable, Halt, Start, Stop. Additionally, there are DIM commands for shutting down the node, setting a parameter value, and wrapping a \dabc~ command as string representation ({\em "ManagerCommand"} for \func{SendOverCommandChannel()}, see section \ref{prog_manager_controls_manager}), resp. Moreover, a \dabc~ module may register a \class{dabc::Command} as new control system command on the fly. In this case \class{dimc::Manager} method \func{CommandRegistration()} will use \func{RegisterModuleCommand()} of \class{dimc::Registry}. This will both define a \class{DimCommand}, and publish a corresponding command descriptor as DIM service to announce the command structure to the generic Java GUI. Method \func{UnRegisterModuleCommand()} may remove command and descriptor service again. When the DIM server receives a remote command, method \func{HandleDIMCommand()} checks if this command is registered; then \func{OnDIMCommand()} will transform the \class{DimCommand} into a \class{dabc::Command} and \func{Submit()} this to the Manager. The actual command execution will thus happen in re-implemented method \func{ExecuteCommand()} of \class{dimc::Manager}. Thus the command action runs independent of the DIM commandhandler thread. \item \strong{Parameter subscription:} Method \func{Subscribe()} (\func{Unsubscribe()}, resp.) of \class{dimc::Manager} are forwarded to \func{SubscribeParameter()} (UnsubscribeParameter() , resp. ) of \class{dimc::Registry}. These implement it by means of the \class{DimService} update mechanism. Subscriptions are kept as vector of \class{dimc::DimParameterInfo} objects (see section \ref{prog_manager_controls_DIM_parinfo}). \item \strong{Remote command execution:} Method \func{SendOverCommandChannel()} of \class{dimc::Manager} is forwarded to \func{SendDimCommand()} of \class{dimc::Registry}. The streamed \class{dabc::Command} is wrapped as text argument into the DIM {\em ManagerCommand} and send to the destination by node name via \func{DimClient::sendCommand()}. \end{compactenum} \subsubsection{\class{dimc::Server}} \label{prog_manager_controls_DIM_server} \index{DIM Control classes ! dimc::Server} Subclass of DIM class \class{DimServer}, implementing command handler, error handler, and exit handlers for client and server exit events. \begin{compactenum} \item Because most DIM server actions are invoked by static methods of \class{DimServer}, it is reasonable to have only one instance of \class{dimc::Server}; thus this class is designed as \strong{singleton pattern}. Access and initial creation is provided by method \func{Instance()}. A safe cleanup is granted by \func{Delete()} (ctors and dtors are private and cannot be invoked directly). \item The \class{dimc::Registry} is set as "owner" of \class{dimc::Server} by means of a back pointer. All handler methods of the \class{DimServer} are implemented as forward calls to corresponding methods of the \class{dimc::Registry} and treated there, such as: \bcir \item \func{commandHandler()} to \func{HandleDIMCommand()} \item \func{errorHandler()} to \func{OnErrorDIMServer()} \item \func{clientExitHandler()} to \func{OnExitDIMClient()} \item \func{exitHandler()} to \func{OnExitDIMServer()} \ecir \end{compactenum} \subsubsection{\class{dimc::ServiceEntry}} \label{prog_manager_controls_DIM_servicentry} \index{DIM Control classes ! dimc::ServiceEntry} This is a container to keep the \class{DimService} together with the corresponding \class{dabc::Parameter} object and some extra properties. The \class{dimc::ServiceEntry} objects are managed by the \class{dimc::Registry} and applied for the \func{RegisterParameter()} method. \begin{compactenum} \item For \class{std::string} parameters an internal \class{char*} array is used as buffer which is actually exported as DIM service. \item Method \func{UpdateBuffer()} updates the DIM service; it optionally may copy the parameter contents to the buffer before. \item Method \func{SetValue()} sets the \class{dabc::Parameter} to a new value, as defined by a string expression. \end{compactenum} \subsubsection{\class{dimc::ParameterInfo}} \label{prog_manager_controls_DIM_parinfo} \index{DIM Control classes ! dimc::ParameterInfo} A subclass of DIM class \class{DimStampedInfo} which subscribes to be informed if a remote DIM service changes its value. The \class{dimc::ParameterInfo} objects are managed by the \class{dimc::Registry} and applied for the \func{Subscribe()} method. \begin{compactenum} \item The \class{dimc::ParameterInfo} has a reference to a local \class{dabc::Parameter} object that shall be updated if the subscribed service changes. \item Depending on the subscribing \class{dabc::Parameter} type (integer, double, string,...), the constructor will instantiate an appropriate \class{DimStampedInfo} type. \item Method \func{infoHandler()} of \class{DimStampedInfo} is implemented to update the parameter to the new value by means of an \func{InvokeChange()} call. \end{compactenum}