388 lines
18 KiB
TeX
388 lines
18 KiB
TeX
\subsection{The Device Executor}
|
|
The Device Executor (devexec) is a core component of the system. It has to
|
|
fulfill three main tasks:
|
|
\begin{itemize}
|
|
\item Permit non--blocking hardware operations.
|
|
\item Ensure regular monitoring of running devices.
|
|
\item Ensure that only one client controls the hardware.
|
|
\end{itemize}
|
|
The devexec in its current form monitors driving and counting
|
|
operations only. The emonitor implements another monitor for
|
|
environment controllers.
|
|
|
|
Please note, that this module is quite crucial for the functioning of
|
|
SICS. Any changes here may have side effects throughout the whole
|
|
system. Be VERY careful with any changes. The current version does its job!
|
|
|
|
Some users want to continue typing commands while some hardware device is
|
|
still running. This is sensible, because some hardware devices require a
|
|
lot of time before they run to completion. Some people also require to count
|
|
while driving motors for quick overview measurements. This requirement was
|
|
the main reason for the invention of the devexec.
|
|
|
|
Of course, when devices are in operation it is needed to check on them
|
|
regularly in order to catch and report error conditions and in order to
|
|
find out when devices are finished with their job.
|
|
|
|
In a client server system many clients might issue commands to the hardware.
|
|
This could quickly lead into an undesirable form of chaos (There are
|
|
desirable forms of chaos, but not here!). In order to prevent this a means
|
|
is needed to ensure that at any given time only one client controls the
|
|
hardware. This function is also performed by the devexec.
|
|
|
|
The device executor also has to take care of special error conditions.
|
|
|
|
\subsubsection{Starting Devices}
|
|
These are the most important SICS operations. Environment controllers are
|
|
monitored by the environment monitor. Then here is a convention: {\bf Any
|
|
SICS object which
|
|
initiates driving or counting operations has to do so by registering this
|
|
operation with the devexec}. For this purpose the following interface
|
|
functions are provided.
|
|
|
|
\begin{flushleft} \small
|
|
\begin{minipage}{\linewidth} \label{scrap1}
|
|
$\langle$devreg {\footnotesize ?}$\rangle\equiv$
|
|
\vspace{-1ex}
|
|
\begin{list}{}{} \item
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@ int StartDevice(pExeList self, char *name, pObjectDescriptor pDes,@\\
|
|
\mbox{}\verb@ void *pData, SConnection *pCon, int level, float fNew);@\\
|
|
\mbox{}\verb@ int StartMotor(pExeList self, SicsInterp *pSics, SConnection *pCon,@\\
|
|
\mbox{}\verb@ char *name, int level, float fNew);@\\
|
|
\mbox{}\verb@ int StartCounter(pExeList self, SicsInterp *pSics, SConnection *pCon,@\\
|
|
\mbox{}\verb@ int level, char *name); @\\
|
|
\mbox{}\verb@@$\Diamond$
|
|
\end{list}
|
|
\vspace{-1ex}
|
|
\footnotesize\addtolength{\baselineskip}{-1ex}
|
|
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
|
\item Macro referenced in scrap ?.
|
|
\end{list}
|
|
\end{minipage}\\[4ex]
|
|
\end{flushleft}
|
|
The main interface function is {\bf StartDevice}. The parameters are:
|
|
\begin{itemize}
|
|
\item {\bf self}. A pointer to the device executor in which SICS operates.
|
|
\item {\bf name}. The name of the object which operates.
|
|
\item {\bf pDes}. A pointer to the ObjectDescriptor of the object to drive or count.
|
|
\item {\bf pData}. A pointer to the data structure coming with the object.
|
|
\item {\bf level} The start level of the device.
|
|
\item {\bf pCon}. A pointer to the client connection on whose request the
|
|
operation was initiated.
|
|
\item {\bf fNew}. A floating point value which sets the target value for
|
|
drivable devices.
|
|
\end{itemize}
|
|
{\bf StartMotor, StartCounter} are just convenience wrappers around
|
|
StartDevice which retrieve objects from the SICS interpreter and calls
|
|
StartDevice thereafter.
|
|
|
|
Once invoked StartDevice takes care of the following operations:
|
|
\begin{itemize}
|
|
\item It first checks on the connection object. If nobody else is running
|
|
hardware it enters the connection object specifed as owner of the devexec in
|
|
its data structure. If an owner was already specified by a prior drive or
|
|
count request StartDevice checks if the connection requesting the new
|
|
operation is the same. If this is not the case, an error message about this
|
|
situation will be issued. If it is the case, i. e. the client requesting the
|
|
new operation is the same as the one who has reserved the devexec, the
|
|
operation is performed. This scheme reserves the devexec to one client.
|
|
\item If the authorisation is OK, StartDevice then proceeds to start the
|
|
drive or counting operation.
|
|
\item StartDevice then enters all information regarding
|
|
the running device into an list for future monitoring.
|
|
\item If it not already running a DevExecTask is registered with the
|
|
task module in order to ensure the monitoring of the devices running.
|
|
\end{itemize}
|
|
|
|
\subsubsection{Monitoring devices}
|
|
|
|
From within the SICS main loops this special function is called:
|
|
\begin{flushleft} \small
|
|
\begin{minipage}{\linewidth} \label{scrap2}
|
|
$\langle$devcheck {\footnotesize ?}$\rangle\equiv$
|
|
\vspace{-1ex}
|
|
\begin{list}{}{} \item
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@ int CheckExeList(pExeList self);@\\
|
|
\mbox{}\verb@ /*@\\
|
|
\mbox{}\verb@ checks the entries for success and deletes entries which have finished@\\
|
|
\mbox{}\verb@ operation. If there are none left, the pOwner will be set to NULL.@\\
|
|
\mbox{}\verb@ */ @\\
|
|
\mbox{}\verb@ int Wait4Success(pExeList self);@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@ long GetDevexecID(pExeList self);@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@ int DevExecLevelRunning(pExeList self, int level);@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@ int DevExecTask(void *pEL);@\\
|
|
\mbox{}\verb@ void DevExecSignal(void *pEL, int iSignal, void *pSigData);@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@ int GetDevExecInstStatus(pExeList self);@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@@$\Diamond$
|
|
\end{list}
|
|
\vspace{-1ex}
|
|
\footnotesize\addtolength{\baselineskip}{-1ex}
|
|
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
|
\item Macro referenced in scrap ?.
|
|
\end{list}
|
|
\end{minipage}\\[4ex]
|
|
\end{flushleft}
|
|
CheckExeList then scan through its list of executing objects and request a
|
|
status from each of them. The next action depend on the status returned from
|
|
the device and any pending interrupts:
|
|
\begin{itemize}
|
|
\item If the device is still busy and no interrupts are pending, nothing
|
|
happens.
|
|
\item If there is a hardware error, this will be reported and apropriate
|
|
actions are intitiated depending on the type of problem and possible
|
|
interrupts being sets.
|
|
\item If a device is done, either naturally or due to an error or interrupt,
|
|
it is removed from devexec's list.
|
|
\item If the list is empty, the owner field of the devexec's datastructure
|
|
is reset to NULL. Then a new client is free to grab control over the
|
|
hardware.
|
|
\end{itemize}
|
|
|
|
{\bf DevExecTask} is the task function for the device executor. Calls
|
|
CheckExeList in the end. If all devices registered with the devexec
|
|
are finished running this function returns 0 and thus stops.
|
|
|
|
{\bf DevExecSignal} is the signal function for the device executor task.
|
|
|
|
{\bf Wait4Success} This function waits for the DevExecTask to
|
|
end. This is the case when the current devices running are finished.
|
|
There are occasions in the program where it is needed to wait for
|
|
an operation to complete before other tasks can be tackled. Wait4Success is
|
|
the function to call in such cases. Wait4Success returns DEVDONE for a
|
|
properly finished operation, DEVERROR for an operation which finished
|
|
with an error code and DEVINT for an aoperation which was interrupted
|
|
by the user.
|
|
|
|
{\bf DevExeclevelRunning} tests if the level given as a parameter is still running.
|
|
|
|
\subsubsection{Influencing Execution}
|
|
In certain cases it is necessary to interact with running devices directly.
|
|
This is done via the following interface.
|
|
|
|
\begin{flushleft} \small
|
|
\begin{minipage}{\linewidth} \label{scrap3}
|
|
$\langle$devstop {\footnotesize ?}$\rangle\equiv$
|
|
\vspace{-1ex}
|
|
\begin{list}{}{} \item
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@ int StopExe(pExeList self, char *name);@\\
|
|
\mbox{}\verb@ int StopExeWait(pExeList self);@\\
|
|
\mbox{}\verb@ /*@\\
|
|
\mbox{}\verb@ will stop the entry name and its subentries from executing.@\\
|
|
\mbox{}\verb@ If ALL is specified as name, everything will be stopped and@\\
|
|
\mbox{}\verb@ the Executor cleared.@\\
|
|
\mbox{}\verb@ StopExeWait will stop all running things and wait for the stop@\\
|
|
\mbox{}\verb@ to complete.@\\
|
|
\mbox{}\verb@ */@\\
|
|
\mbox{}\verb@ int StopByData(pExeList self, void *data);@\\
|
|
\mbox{}\verb@ /* stop the entry with the given data from execution */@\\
|
|
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
|
|
\mbox{}\verb@ void ClearExecutor(pExeList self);@\\
|
|
\mbox{}\verb@ /*@\\
|
|
\mbox{}\verb@ clears the executor without sending commands to the devices.@\\
|
|
\mbox{}\verb@ */@\\
|
|
\mbox{}\verb@/*-----------------------------------------------------------------------*/@\\
|
|
\mbox{}\verb@ int IsCounting(pExeList self);@\\
|
|
\mbox{}\verb@ int PauseExecution(pExeList self);@\\
|
|
\mbox{}\verb@ int ContinueExecution(pExeList self);@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@@$\Diamond$
|
|
\end{list}
|
|
\vspace{-1ex}
|
|
\footnotesize\addtolength{\baselineskip}{-1ex}
|
|
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
|
\item Macro referenced in scrap ?.
|
|
\end{list}
|
|
\end{minipage}\\[4ex]
|
|
\end{flushleft}
|
|
{\bf StopExe} tackles the interrupting of pending operations. This may
|
|
happen on a users request. StopExe then invokes a halt on that device.
|
|
As parameters, the name of a device to stop can be specified. If ALL is
|
|
given as name to StopExe all executing devices are stopped. Please note, that
|
|
this stop does not automatically finish the operation. Motors need some time
|
|
to stop, too. This function is usally called as consequence of an
|
|
interrupt.
|
|
|
|
|
|
{\bf ClearExecutor} clears the executor without invoking commands on the
|
|
devices. Is probably only used internally to clean out the executor.
|
|
|
|
I some cases, for example if a environment controller gets out of range, an
|
|
error handling strategy may want to pause counting until the problem has
|
|
been rectified and continue afterwards. {\bf PauseExecution, ContinueExecution}
|
|
take care of invoking the apropriate commands on all registered counting
|
|
devices.
|
|
|
|
|
|
\subsubsection{Locking the Device Executor}
|
|
In some instances user code may wish to lock the device executor. An
|
|
example is a long running data saving operation. In order to do this
|
|
two functions are provided:
|
|
|
|
\begin{flushleft} \small
|
|
\begin{minipage}{\linewidth} \label{scrap4}
|
|
$\langle$devlock {\footnotesize ?}$\rangle\equiv$
|
|
\vspace{-1ex}
|
|
\begin{list}{}{} \item
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@ void LockDeviceExecutor(pExeList self);@\\
|
|
\mbox{}\verb@ void UnlockDeviceExecutor(pExeList self);@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@@$\Diamond$
|
|
\end{list}
|
|
\vspace{-1ex}
|
|
\footnotesize\addtolength{\baselineskip}{-1ex}
|
|
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
|
\item Macro referenced in scrap ?.
|
|
\end{list}
|
|
\end{minipage}\\[4ex]
|
|
\end{flushleft}
|
|
\subsubsection{The Rest}
|
|
The rest of the interface includes initialisation and deletion routines
|
|
and some access routines. With the devexec being such an important system
|
|
component a function {\bf GetExecutor} is provided which retrieves a pointer
|
|
to the global SICS device executor.
|
|
|
|
\begin{flushleft} \small
|
|
\begin{minipage}{\linewidth} \label{scrap5}
|
|
\verb@"devexec.h"@ {\footnotesize ? }$\equiv$
|
|
\vspace{-1ex}
|
|
\begin{list}{}{} \item
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@/*----------------------------------------------------------------------------@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@ D E V I C E E X E C U T O R@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@ Joachim Kohlbrecher wants to give several commands to the server@\\
|
|
\mbox{}\verb@ and than wait for them to happen before proceeding. Actually a useful@\\
|
|
\mbox{}\verb@ thing. A command will map to one or several positioning commands for a@\\
|
|
\mbox{}\verb@ device. This scheme is also useful for implementing objects which@\\
|
|
\mbox{}\verb@ drive several motors simulataneously, such as Monochromators. etc.@\\
|
|
\mbox{}\verb@ However, the whole thing is rather complicated.@\\
|
|
\mbox{}\verb@ @\\
|
|
\mbox{}\verb@ It is forbidden, that several clients drive the instrument. In order@\\
|
|
\mbox{}\verb@ to ensure this the Executor remembers the connection which emitted the@\\
|
|
\mbox{}\verb@ first command. Subsequent AddExeEntries from different clients will@\\
|
|
\mbox{}\verb@ be rejected. The owner will be reset when the execution is found finished@\\
|
|
\mbox{}\verb@ in calls to CheckExe, Wait4Success or StopExe.@\\
|
|
\mbox{}\verb@ @\\
|
|
\mbox{}\verb@ @\\
|
|
\mbox{}\verb@ Mark Koennecke, December 1996@\\
|
|
\mbox{}\verb@ @\\
|
|
\mbox{}\verb@ copyright: see implementation file@\\
|
|
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
|
|
\mbox{}\verb@#ifndef SICSDEVEXEC@\\
|
|
\mbox{}\verb@#define SICSDEVEXEC@\\
|
|
\mbox{}\verb@#include "obdes.h"@\\
|
|
\mbox{}\verb@#include "task.h"@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@ typedef struct __EXELIST *pExeList;@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@/* Returncodes */@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@#define DEVDONE 1@\\
|
|
\mbox{}\verb@#define DEVINT 0@\\
|
|
\mbox{}\verb@#define DEVERROR 2@\\
|
|
\mbox{}\verb@#define DEVBUSY 3@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@/* run level codes */@\\
|
|
\mbox{}\verb@#define RUNRUN 0@\\
|
|
\mbox{}\verb@#define RUNDRIVE 1@\\
|
|
\mbox{}\verb@/*------------------------------------------------------------------------@\\
|
|
\mbox{}\verb@ B I R T H & D E A T H@\\
|
|
\mbox{}\verb@*/@\\
|
|
\mbox{}\verb@ pExeList CreateExeList(pTaskMan pTask);@\\
|
|
\mbox{}\verb@ void DeleteExeList(void *self);@\\
|
|
\mbox{}\verb@ @\\
|
|
\mbox{}\verb@/* ================= Functions to talk to the above ====================== */@\\
|
|
\mbox{}\verb@@$\langle$devreg {\footnotesize ?}$\rangle$\verb@@\\
|
|
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
|
|
\mbox{}\verb@@$\langle$devcheck {\footnotesize ?}$\rangle$\verb@@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@ /*@\\
|
|
\mbox{}\verb@ Waits for execution to finish. returns 1 on Success, 0 if problems@\\
|
|
\mbox{}\verb@ ocurred. Than the Interrupt code shall be checked and acted upon@\\
|
|
\mbox{}\verb@ accordingly.@\\
|
|
\mbox{}\verb@ */@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
|
|
\mbox{}\verb@ SConnection *GetExeOwner(pExeList self);@\\
|
|
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
|
|
\mbox{}\verb@ int isInRunMode(pExeList self);@\\
|
|
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
|
|
\mbox{}\verb@ int ListPending(pExeList self, SConnection *pCon);@\\
|
|
\mbox{}\verb@ /*@\\
|
|
\mbox{}\verb@ lists the Operations still pending on pCon. @\\
|
|
\mbox{}\verb@ */@\\
|
|
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
|
|
\mbox{}\verb@@$\langle$devstop {\footnotesize ?}$\rangle$\verb@@\\
|
|
\mbox{}\verb@/*-------------------------- Commands ------------------------------------*/@\\
|
|
\mbox{}\verb@ int DevexecAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
|
|
\mbox{}\verb@ int argc, char *argv[]);@\\
|
|
\mbox{}\verb@ int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
|
|
\mbox{}\verb@ int argc, char *argv[]);@\\
|
|
\mbox{}\verb@ /*@\\
|
|
\mbox{}\verb@ implements the stop command@\\
|
|
\mbox{}\verb@ */@\\
|
|
\mbox{}\verb@ @\\
|
|
\mbox{}\verb@ int ListExe(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
|
|
\mbox{}\verb@ int argc, char *argv[]);@\\
|
|
\mbox{}\verb@ /*@\\
|
|
\mbox{}\verb@ lists all currently executing objects@\\
|
|
\mbox{}\verb@ */@\\
|
|
\mbox{}\verb@ int SicsIdle(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
|
|
\mbox{}\verb@ int argc, char *argv[]);@\\
|
|
\mbox{}\verb@ /*@\\
|
|
\mbox{}\verb@ prints the seconds since the device executor was running the last time@\\
|
|
\mbox{}\verb@ */@\\
|
|
\mbox{}\verb@@\\
|
|
\mbox{}\verb@ int Success(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
|
|
\mbox{}\verb@ int argc, char *argv[]);@\\
|
|
\mbox{}\verb@ /*@\\
|
|
\mbox{}\verb@ waits until completion of all pending operations. Used in@\\
|
|
\mbox{}\verb@ connection with non blocking operation such as motors started@\\
|
|
\mbox{}\verb@ with run.@\\
|
|
\mbox{}\verb@ */@\\
|
|
\mbox{}\verb@ int PauseAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
|
|
\mbox{}\verb@ int argc, char *argv[]);@\\
|
|
\mbox{}\verb@ /*@\\
|
|
\mbox{}\verb@ pauses execution@\\
|
|
\mbox{}\verb@ */@\\
|
|
\mbox{}\verb@ int ContinueAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
|
|
\mbox{}\verb@ int argc, char *argv[]);@\\
|
|
\mbox{}\verb@ /*@\\
|
|
\mbox{}\verb@ continues execution@\\
|
|
\mbox{}\verb@ */ @\\
|
|
\mbox{}\verb@ @\\
|
|
\mbox{}\verb@/*--------------------------- Locking ---------------------------------*/@\\
|
|
\mbox{}\verb@ @$\langle$devlock {\footnotesize ?}$\rangle$\verb@ @\\
|
|
\mbox{}\verb@/* -------------------------- Executor management -------------------------*/@\\
|
|
\mbox{}\verb@ @\\
|
|
\mbox{}\verb@ pExeList GetExecutor(void);@\\
|
|
\mbox{}\verb@ void SetExecutor(pExeList pExe);@\\
|
|
\mbox{}\verb@ @\\
|
|
\mbox{}\verb@ /**@\\
|
|
\mbox{}\verb@ * This is only used in sicshdbadapter.c@\\
|
|
\mbox{}\verb@ * It became a void pointer because of circular dependencies in the @\\
|
|
\mbox{}\verb@ * header files.@\\
|
|
\mbox{}\verb@ */ @\\
|
|
\mbox{}\verb@ void *GetExecutorCallback(pExeList self);@\\
|
|
\mbox{}\verb@/*----------------------- Logging -----------------------------------------*/@\\
|
|
\mbox{}\verb@ void DevexecLog(char *op, char *device);@\\
|
|
\mbox{}\verb@ void ExeInterest(pExeList pExe, char *name, char *action); @\\
|
|
\mbox{}\verb@ void InvokeNewTarget(pExeList pExe, char *name, float fTarget);@\\
|
|
\mbox{}\verb@ void SetDevexecStatus(pExeList pExe, int code);@\\
|
|
\mbox{}\verb@#endif @\\
|
|
\mbox{}\verb@@$\Diamond$
|
|
\end{list}
|
|
\vspace{-2ex}
|
|
\end{minipage}\\[4ex]
|
|
\end{flushleft}
|