# Changeset 10280

Ignore:
Timestamp:
04/01/11 09:39:25 (11 years ago)
Message:
Separated Edd into generic Evidence part and FACT-specific part
Location:
fact
Files:
1 deleted
1 edited
3 copied

Unmodified
Removed
• ## fact/Evidence/Doc/Evidence.tex

 r262 \usepackage{url} \usepackage{listings} \usepackage[light]{draftcopy} %\usepackage[light]{draftcopy} \usepackage{longtable} \maketitle This report describes the design and basic functionality of the \E control system. This essentially is a C++ class and a set of programs running on Linux for controlling small scale experiments. It is based on CERN's DIM library for interprocess communication over TCP/IP connections. \lstinline{$Rev$} This report describes the design and basic functionality of the \E control system. This essentially is a C++ class and a set of programs running on Linux for controlling small scale experiments. It is based on CERN's DIM library for interprocess communication over TCP/IP connections. \tableofcontents \label{Overview} The \E control system has been developed for application in small-scale experiments, for which established and comprehensive control systems like EPICS, DOOCS or PVS-II are too large and impose too much overburden.\footnote{Information on these systems can be found at \url{http://www.aps.anl.gov/epics/}, \url{http://tesla.desy.de/doocs}, \url{http://www.etm.at/}.} The development of \E has been started within the FACT project (\emph{First G-APD Cherenkov Telescope} \cite{Bra09,And10}). The \E control system has been developed for application in small-scale experiments, for which established and comprehensive control systems like EPICS, DOOCS or PVS-II are too large and impose too much overburden.\footnote{Information on these systems can be found at \url{http://www.aps.anl.gov/epics/}, \url{http://tesla.desy.de/doocs}, \url{http://www.etm.at/}.} The development of \E has been started within the FACT project (\emph{First G-APD Cherenkov Telescope} \cite{Bra09,And11}). An experiment control system often comprises several individual programs that require configuration information, produce data that should be stored and easily visualized, and at least partly need to exchange information between each other. The intention of \E is to a) integrate this with a minimum of extra coding on part of the applications, b) to achieve this using as far as reasonable established tools, c) to be centralized\footnote{This is a design choice that partly defines the range of applicable experiments. For large systems decentralization can be a better approach.}, and d) to be lean. \item Provides a method for configuration requests. If the configuration data is not available, the application terminates with a  message of FATAL severity unless default data is given. \item Provides a method for safely translating DIM service data into text. \item Implements the virtual DIM methods \lstinline{exitHandler()}. It can be called through a standard DIM command \lstinline{SvrName/EXIT}, taking a single integer as argument. Upon first invocation, the handler just sets the flag \lstinline{ExitRequest} which should be handled by the application. Upon second invocation, it will call \lstinline{exit()}. The user application can override this handler. \item Implements the virtual DIM methods \lstinline{exitHandler()}. It can be called through a standard DIM command \lstinline{SvrName/EXIT}, taking a single integer as argument. The handler will issue a message with severity \lstinline{INFO}, including the received integer, and then calls \lstinline{exit(EXIT_SUCCESS)}. The user application can override this handler. \item Provides a DIM command \lstinline{SvrName/ResetMessage}. It will set the message service to INFO severity with the information which client issued the command. This can be used to remove a WARN, ERROR or FATAL serverity once the problem has been fixed. The \lstinline{Alarm} server uses this command if it is instructed to reset an alarm level. The command takes no arguments. \item Implements the virtual DIM methods \lstinline{errorHandler()}. The error handler will issue a message with ERROR severity that contains the DIM error code. The user application can override this handler. ~EvidenceServer(); enum MessageType {INFO=0, WARN=1, ERROR=2, FATAL=3}; void Message(MessageType, const char *, ...); enum MessageType {INFO=0, WARN=10, ERROR=20, FATAL=30}; void Message(int, const char *, ...); void SendToLog(const char *, ...); string GetConfig(string, string = string()); static bool ServiceOK(DimInfo *); static bool ServiceOK(DimRpcInfo *); static bool ServiceOK(DimCurrentInfo *); static bool ServiceOK(DimCurrentInfo *); static vector Tokenize(const string &, const string & = " "); \underline{\lstinline{GetConfig()}} issues, on first invocation, a DIM remote procedure call to the configuration server to retrieve the required data and returns it as a string. The second argument gives the data to be returned in case the server is unavailable or cannot provide the requested data. If in this case the second string is empty, the program terminates with a FATAL message. Using the service \lstinline{Config/ModifyTime}, the server keeps track of changes to the configuration file in the background. Upon subsequent requests for the same configuration data, it only issues a remote procedure call again if the file changed in the meantime. If not, the same data already retrieved is returned. This way, this function can be repeatedly called, even at high rate, without generating unnecessary load to the configuration server (as the configuration file does not change frequently). The virtual method \underline{\lstinline{ConfigChanged()}} is executed in a separate thread when the configuration file changes. It can be reimplemented by the application. Calls to \lstinline{GetConfig()} from this method will be blocking and thus result in updated configuration data. The virtual method \underline{\lstinline{ConfigChanged()}} is executed in a separate thread when the configuration file changes. It can be reimplemented by the application. Calls to \lstinline{GetConfig()} from this method will be blocking and thus result in immediately updated configuration data. See Sect.\,\ref{ConfigHandling} for more details. The methods \underline{\lstinline{Lock()}} and \underline{\lstinline{Unlock()}} work on an internal mutex.\footnote{Its type is \lstinline{PTHREAD_MUTEX_ERRORCHECK}. In case an already locked mutex is re-locked, the corresponding system call will therefore return a error and thus avoid dead-locking. Error messages from \lstinline{Lock()} and \lstinline{Unlock()} are written to the console and to the log file. They are not published using \lstinline{Message()} since this method itself uses locking and calling it would result in an infinite recursion.} They are used by \lstinline{GetConfig()} but are also available for the user application to serialize access from multiple threads. Calling functions in the locked state should be avoided as it might result in re-locking. \subsection{\lstinline{Alarm} --- Handling of error conditions} The alarm server maintains a list of \emph{alarm levels} for a given set of servers. The alarm levels are defined as \lstinline{OK} (0), \lstinline{WARN} (1), \lstinline{ERROR} (2), \lstinline{FATAL} (3), and \lstinline{UNAVAILABLE} (4). The first four result from the corresponding severities of the message services, to which the alarm server subscribes. The alarm level does not decrease if, for example, a server issues a message with severity \lstinline{WARN} after one with \lstinline{ERROR}. It is only reset by command or by restarting the alarm server. The alarm server maintains a list of \emph{alarm levels} for a given set of servers. The standard alarm levels are defined as \lstinline{OK} (0), \lstinline{WARN} (10), \lstinline{ERROR} (20), \lstinline{FATAL} (30), and \lstinline{UNAVAILABLE} (40). The first four result from the corresponding severities of the message services, to which the alarm server subscribes. The alarm level does not decrease if, for example, a server issues a message with severity \lstinline{WARN} after one with \lstinline{ERROR}. Only if a server changes from \lstinline{UNAVAILABLE} to \lstinline{OK} (by restarting) or through the command \lstinline|ResetAlarm| can the alarm level be lowered. A master alarm is generated from the highest server alarm level. The alarm server also periodically checks if all required servers are up (searching for them with the DIM browser). It can send an email in case a server is down or in error. One email will be send with each increase of alarm level for each server. \lstinline|period| & Interval in seconds to check for server availability.\\[1ex] \multicolumn{2}{l}{\textbf{Commands}} \\ \lstinline|ResetAlarm xyz| & Reset alarm level of server \lstinline|xyz|.\\[1ex] \lstinline|ResetAlarm xyz| & Reset alarm level of server \lstinline|xyz|.\\ \lstinline|Switch on/off| & Switch alarm server on or off.\\[1ex] \multicolumn{2}{l}{\textbf{Services}} \\ \lstinline|Alarm/Summary| & Text listing all observed servers and their alarm level.\\ As a first step in achieving this, the application should not store the obtained configuration data internally, but always re-request it using the method \lstinline{GetConfig()} described in Sect.\,\ref{EvidenceServer-Methods}. This method will only issue a remote procedure call to the \lstinline{Config} server if the configuration file has been modified since the last invocation. So calling this method even at high rate will not load the configuration server at all if the configuraton file is unchanged, but will yield up-to-date information if it did change. The remote procedure call is blocking when called from the main thread or from the method \lstinline{ConfigChanged()} (which runs in a separate thread). It is non-blocking, using an \lstinline{rpcInfoHandler()}, when called from any other thread, especially also from the DIM handler thread. Blocking execution means that the remote procedure call will wait until the data has arrived from the server before returning to the application, whereas non-blocking execution will return immediately and invoke a handler later when the data arrived. This procedure is necessary since a blocking remote procedure call from \lstinline{infoHandler()} will result in a dead-lock. The remote procedure call is non-blocking (using an \lstinline{rpcInfoHandler()}) when invoked from the DIM handler thread and blocking otherwise. Blocking execution means that the remote procedure call will wait until the data has arrived from the server before returning to the application, whereas non-blocking execution will return immediately and invoke an internal handler later when the data arrived. This procedure is necessary since a blocking remote procedure call from the DIM handler thread (e.g. from an \lstinline{infoHandler()}) will result in a dead-lock. In the non-blocking case, the call to \lstinline{GetConfig()} returns still the previous, non-updated data even if the configuration file changed. The result of the non-blocking remote procedure call can only be processed by DIM once the current and all queued handler invocations have finished. When this is done, updated data will be returned by subsequent calls to \lstinline{GetConfig()}. An alternative, albeit for the programmer more demanding, procedure for semi-automatic updates on configuration information is to reimplement the virtual method \lstinline{ConfigChanged()} in the user class. This method is invoked as a separate thread by the \lstinline{EvidenceServer} class whenever the service \lstinline{Config/ModifyTime} changes (and also at program start-up). As it is not running within the DIM handler thread, \lstinline{GetConfig()} will use blocking connections to get immediately up-to-date data when called from \lstinline{ConfigChanged()}. Running in a separate thread requires suitable protection by the programmer when accessing common data structures. To ease that, the \lstinline{EvidenceServer} class contains the pair of methods \lstinline{Lock()} and \lstinline{Unlock()} that work on an class internal mutex. The mutex type is \lstinline{PTHREAD_MUTEX_ERRORCHECK} and therefore includes error checking: no dead-lock will occur if double locking, but the program will terminate with a \lstinline{FATAL} message. Running in a separate thread requires suitable protection by the programmer when accessing common data structures. To ease that, the \lstinline{EvidenceServer} class contains the methods \lstinline{Lock()} and \lstinline{Unlock()} that work on an class internal mutex. The mutex type is \lstinline{PTHREAD_MUTEX_ERRORCHECK} and therefore includes error checking: no dead-lock will occur if double locking, but instead the program will terminate with a \lstinline{FATAL} message. A graphical user interface (GUI), implemented using the Qt and Qwt frameworks\footnote{Information on these frameworks is available at \url{http://qt.nokia.com/} and \url{http://qwt.sourceforge.net/}.}, is available. It derives from standard widget classes extended versions that can display the contents of DIM services and history buffers. A widget to send generic text commands is also available. Qwt is used to display graphs which is not supported by Qt. The GUI is called \emph{Evidence Data Display} (\lstinline{EDD}). It has a single point interface to the DIM system and distributes received service updates to its widgets using the Qt signal/slot mechanism. This is necessary since the DIM \lstinline{infoHandler()} receiving the updates runs in a separate thread, but manipulations of GUI elements within Qt may only be done by the main thread. This mechanism also guarantees that one GUI instance subscribes not more than once to a particular service, even if the same data is shown by multiple widgets. The GUI is called \emph{Evidence Data Display} (\lstinline{Edd}). It has a single point interface to the DIM system and distributes received service updates to its widgets using the Qt signal/slot mechanism. This is necessary since the DIM \lstinline{infoHandler()} receiving the updates runs in a separate thread, but manipulations of GUI elements within Qt may only be done by the main thread. This mechanism also guarantees that one GUI instance subscribes not more than once to a particular service, even if the same data is shown by multiple widgets. The GUI implementation is designed to be easily portable and does not use operating-system specifics. It sticks to standard C++ code, to Qt capabilities and to DIM. Qt is explicitely designed for cross-platform applications. \label{DIMDetails} \subsection{Format of \lstinline{DIM_DNS/SERVER_LIST} and \lstinline{xyz/SERVICE_LIST}} \subsection{Format of \lstinline{DIS_DNS/SERVER_LIST} and \lstinline{xyz/SERVICE_LIST}} \label{ServiceFormats} If server and client use the same structure definition, a cast like \lstinline{struct A *Pnt = getData()} will guarantee correct access to elements. For example, \lstinline{Pnt->b[1]} will contain the second integer, even if client and server pad structures differently. Padding can also be disabled for a server if desired. In general, no blocking functions should be called from within a DIM handler. Specifically, making a blocking remote procedure call in an \lstinline{infoHandler()} will dead lock.\footnote{Non-blocking reception using an \lstinline{rpcInfoHandler()} is possible}. In general, no blocking functions should be called from within a DIM handler. Specifically, making a blocking remote procedure call in an \lstinline{infoHandler()} will dead lock.\footnote{Non-blocking reception using an \lstinline{rpcInfoHandler()} is possible}. This also applies to the \lstinline{exitHandler()}. Calling \lstinline{exit()} from this handler will run destructors of static objects within the DIM thread. This might result in undesirable behaviour if DIM services are deleted in those destructors. If DIM is compiled without threads, it uses internally the signals SIGIO and SIGALRM for communication. \begin{thebibliography}{xxxx00} \bibitem[Gas01]{Gas01} C. Gaspar, M. D\"{o}nszelmann and Ph. Charpentier, \emph{DIM, a portable, light weight package for information publishing, data transfer and inter-process communication}, Computer Physics Communications 140 1+2 102-9, 2001 \bibitem[Bra09]{Bra09} I. Braun et al., Nucl. Inst. and Methods A 610, 400 (2009) \bibitem[And10]{And10} H. Anderhub et al., Nucl. Inst. and Methods, to be published (2010) \bibitem[Gas01]{Gas01} C. Gaspar, M. D\"{o}nszelmann and Ph. Charpentier, \emph{DIM, a portable, light weight package for information publishing, data transfer and inter-process communication}, Computer Physics Communications \textbf{140}, 102 (2001) \bibitem[Bra09]{Bra09} I. Braun et al., Nucl. Inst. and Methods \textbf{A 610}, 400 (2009) \bibitem[And11]{And11} H. Anderhub et al., Nucl. Inst. and Methods, \textbf{A 628}, 107 (2011) \end{thebibliography}
• ## fact/Evidence/Doc/INSTALL_Edd

 r10262 and DIMDIR to the DIM installation. The subversion repository should preferably be checked out fully, as the class describing the M0 raw data format is currently needed. Issue 'qmake', then 'make' will build the executable Edd.
• ## fact/Evidence/GUI.cc

 r10262 #ifndef EDD_H_SEEN #define EDD_H_SEEN #ifndef GUI_H_SEEN #define GUI_H_SEEN #include #include "dic.hxx" #include "Evidence.h" #include "RawDataCTX.h" #include "PixelMap.h" #define SVN_REVISION "$Revision$" const QColor EddPlotBackgroundColor(Qt::yellow); }; // // // ====== FACT specific part ====== // // // Event oscilloscope class EventScope: public EddBasePlot, public PixelMap { Q_OBJECT private: struct ItemDetails { unsigned int Board, Chip, Channel; QwtPlotCurve *Signal; QwtPlotMarker *Trigger; }; QList List; QString Name; RawDataCTX *RD; CTX_ErrCode ErrCode; QAction *PhysPipeAction; QAction *PersistanceAction; FILE *Tmpfile; public: EventScope(QWidget * = NULL); ~EventScope(); void UpdateFirst(int, int, int); void AddTrace(int, int, int); void SetActive(bool); QString ToPixel(unsigned int, unsigned int, unsigned int, unsigned int); private slots: void Update(QString, int, QByteArray, QString, QString); void PlotTraces(); void DeleteCurve(QwtPlotCurve *); signals: void RunHeaderChanged(QString); void EventHeaderChanged(QString); void PixelData(QVector); }; // Tab page classes class TP_Environment: public QWidget { Q_OBJECT public: TP_Environment(); }; class TP_Bias: public QWidget { Q_OBJECT private slots: void BiasCurrents(); public: TP_Bias(); }; class TP_FADctrl: public QWidget { Q_OBJECT public: TP_FADctrl(); }; class TP_Feedback: public QWidget { Q_OBJECT private slots: void FeedbackDetails(); public: TP_Feedback(); }; class TP_DAQ: public QWidget { Q_OBJECT static const int MAXPIXEL = 1440; private: EventScope *Scope; QPlainTextEdit *RunHeaderDisplay, *EventHeaderDisplay; QSpinBox *Channel, *Chip, *Board, *PixelID; QFormLayout *FormLayout; QWidget *Display; QPushButton **Pixel; QPushButton *StartStopButton; private slots: void TranslatePixelID(int); void UpdateScope(int); void KeepCurrent(); void StartStop(bool); void ShowPixelDisplay(); void SetPixelData(QVector); public: TP_DAQ(); ~TP_DAQ(); }; class TP_Evidence: public QWidget { Q_OBJECT private slots: void ToggleAlarm(bool); void StartDIMBrowser(); void StartELog(); public: TP_Evidence(); }; // Main window class class GUI: public QMainWindow, public DimBrowser { Q_OBJECT private: QWidget *Central; QTabWidget *TabWidget; void closeEvent(QCloseEvent *); public: GUI(); ~GUI(); private slots: void MenuAbout(); void MenuNewHistory(); void DetachTab(int); void CheckAlarm(); // Open new window class EddWindow: public QPushButton { Q_OBJECT QMainWindow *M; QGridLayout *L; public: EddWindow(QString, QString); QGridLayout *Layout(); QMainWindow *Window(); private slots: void Toggle(); };