Initial revision
This commit is contained in:
282
devexec.w
Normal file
282
devexec.w
Normal file
@ -0,0 +1,282 @@
|
||||
\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.
|
||||
|
||||
@d devreg @{
|
||||
int StartDevice(pExeList self, char *name, pObjectDescriptor pDes,
|
||||
void *pData, SConnection *pCon, float fNew);
|
||||
int StartMotor(pExeList self, SicsInterp *pSics, SConnection *pCon,
|
||||
char *name, float fNew);
|
||||
int StartCounter(pExeList self, SicsInterp *pSics, SConnection *pCon,
|
||||
char *name);
|
||||
@}
|
||||
|
||||
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 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:
|
||||
@d devcheck @{
|
||||
int CheckExeList(pExeList self);
|
||||
/*
|
||||
checks the entries for success and deletes entries which have finished
|
||||
operation. If there are none left, the pOwner will be set to NULL.
|
||||
*/
|
||||
int Wait4Success(pExeList self);
|
||||
|
||||
long GetDevexecID(pExeList self);
|
||||
|
||||
int DevExecTask(void *pEL);
|
||||
void DevExecSignal(void *pEL, int iSignal, void *pSigData);
|
||||
|
||||
@}
|
||||
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.
|
||||
|
||||
\subsubsection{Influencing Execution}
|
||||
In certain cases it is necessary to interact with running devices directly.
|
||||
This is done via the following interface.
|
||||
|
||||
@d devstop @{
|
||||
int StopExe(pExeList self, char *name);
|
||||
int StopExeWait(pExeList self);
|
||||
/*
|
||||
will stop the entry name and its subentries from executing.
|
||||
If ALL is specified as name, everything will be stopped and
|
||||
the Executor cleared.
|
||||
StopExeWait will stop all running things and wait for the stop
|
||||
to complete.
|
||||
*/
|
||||
/*------------------------------------------------------------------------*/
|
||||
void ClearExecutor(pExeList self);
|
||||
/*
|
||||
clears the executor without sending commands to the devices.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int IsCounting(pExeList self);
|
||||
int PauseExecution(pExeList self);
|
||||
int ContinueExecution(pExeList self);
|
||||
|
||||
@}
|
||||
|
||||
{\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{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.
|
||||
|
||||
@o devexec.h -d @{
|
||||
/*----------------------------------------------------------------------------
|
||||
|
||||
D E V I C E E X E C U T O R
|
||||
|
||||
Joachim Kohlbrecher wants to give several commands to the server
|
||||
and than wait for them to happen before proceeding. Actually a useful
|
||||
thing. A command will map to one or several positioning commands for a
|
||||
device. This scheme is also useful for implementing objects which
|
||||
drive several motors simulataneously, such as Monochromators. etc.
|
||||
However, the whole thing is rather complicated.
|
||||
|
||||
It is forbidden, that several clients drive the instrument. In order
|
||||
to ensure this the Executor remembers the connection which emitted the
|
||||
first command. Subsequent AddExeEntries from different clients will
|
||||
be rejected. The owner will be reset when the execution is found finished
|
||||
in calls to CheckExe, Wait4Success or StopExe.
|
||||
|
||||
|
||||
Mark Koennecke, December 1996
|
||||
|
||||
copyright: see implementation file
|
||||
---------------------------------------------------------------------------*/
|
||||
#ifndef SICSDEVEXEC
|
||||
#define SICSDEVEXEC
|
||||
#include "obdes.h"
|
||||
#include "task.h"
|
||||
|
||||
typedef struct __EXELIST *pExeList;
|
||||
|
||||
/* Returncodes */
|
||||
|
||||
#define DEVDONE 1
|
||||
#define DEVINT 0
|
||||
#define DEVERROR 2
|
||||
#define DEVBUSY 3
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
B I R T H & D E A T H
|
||||
*/
|
||||
pExeList CreateExeList(pTaskMan pTask);
|
||||
void DeleteExeList(void *self);
|
||||
|
||||
/* ================= Functions to talk to the above ====================== */
|
||||
@<devreg@>
|
||||
/*------------------------------------------------------------------------*/
|
||||
@<devcheck@>
|
||||
|
||||
/*
|
||||
Waits for execution to finish. returns 1 on Success, 0 if problems
|
||||
ocurred. Than the Interrupt code shall be checked and acted upon
|
||||
accordingly.
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
SConnection *GetExeOwner(pExeList self);
|
||||
/*-------------------------------------------------------------------------*/
|
||||
int isInRunMode(pExeList self);
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int ListPending(pExeList self, SConnection *pCon);
|
||||
/*
|
||||
lists the Operations still pending on pCon.
|
||||
*/
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@<devstop@>
|
||||
/*-------------------------- Commands ------------------------------------*/
|
||||
int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
/*
|
||||
implements the stop command
|
||||
*/
|
||||
|
||||
int ListExe(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
/*
|
||||
lists all currently executing objects
|
||||
*/
|
||||
int Success(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
/*
|
||||
waits until completion of all pending operations. Used in
|
||||
connection with non blocking operation such as motors started
|
||||
with run.
|
||||
*/
|
||||
|
||||
/* -------------------------- Executor management -------------------------*/
|
||||
|
||||
pExeList GetExecutor(void);
|
||||
void SetExecutor(pExeList pExe);
|
||||
|
||||
#endif
|
||||
@}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user