450 lines
12 KiB
C
450 lines
12 KiB
C
/*--------------------------------------------------------------------------
|
|
|
|
Just a Status management object. Not very exciting.
|
|
|
|
|
|
Mark Koennecke, November 1996
|
|
added callback facilities and interst command.
|
|
Mark Koennecke, August 1997
|
|
|
|
Updated in order to prevent status floods
|
|
Mark Koennecke, July 2004
|
|
|
|
Reworked restore to keep parameters from uninitialized devices
|
|
Mark Koennecke, November 2007
|
|
|
|
Reworked to determine the status from the state of the machine rather then
|
|
from explicit sets on a global variable. Which caused trouble, trouble and more
|
|
trouble. Mark Koennecke, July 2015
|
|
|
|
Copyright:
|
|
|
|
Labor fuer Neutronenstreuung
|
|
Paul Scherrer Institut
|
|
CH-5423 Villigen-PSI
|
|
|
|
|
|
The authors hereby grant permission to use, copy, modify, distribute,
|
|
and license this software and its documentation for any purpose, provided
|
|
that existing copyright notices are retained in all copies and that this
|
|
notice is included verbatim in any distributions. No written agreement,
|
|
license, or royalty fee is required for any of the authorized uses.
|
|
Modifications to this software may be copyrighted by their authors
|
|
and need not follow the licensing terms described here, provided that
|
|
the new terms are clearly indicated on the first page of each file where
|
|
they apply.
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
|
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
|
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
|
MODIFICATIONS.
|
|
-----------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <time.h>
|
|
#include "fortify.h"
|
|
#include <string.h>
|
|
#include "sics.h"
|
|
#include "status.h"
|
|
#include "interrupt.h"
|
|
#include "sicshipadaba.h"
|
|
#include "messagepipe.h"
|
|
#include "scan.h"
|
|
#include "exeman.h"
|
|
#include "nxscript.h"
|
|
#undef VALUECHANGE
|
|
#define VALUECHANGE 2
|
|
|
|
|
|
static char *pText[] = {
|
|
"Eager to execute commands",
|
|
"User requested Wait",
|
|
"Counting",
|
|
"No Beam",
|
|
"Paused",
|
|
"Driving",
|
|
"Running",
|
|
"Running a scan",
|
|
"Writing data",
|
|
"Processing a batch file",
|
|
"Halted",
|
|
"Dead",
|
|
"Waiting for User Input",
|
|
"Counting/Driving",
|
|
"Working",
|
|
NULL
|
|
};
|
|
|
|
static char *iText[] = {
|
|
"eager",
|
|
"userwait",
|
|
"count",
|
|
"nobeam",
|
|
"paused",
|
|
"driving",
|
|
"running",
|
|
"scanning",
|
|
"writing",
|
|
"batch",
|
|
"halt",
|
|
"dead",
|
|
"input",
|
|
"count/drive",
|
|
"working",
|
|
NULL
|
|
};
|
|
|
|
static pICallBack pCall = NULL;
|
|
static int fixed = 0;
|
|
static Status eCode = eEager;
|
|
static int userWait = 0;
|
|
static double lastStatus = .0;
|
|
/*-------------------------------------------------------------------------*/
|
|
void KillStatus(void *pData)
|
|
{
|
|
if (pCall != NULL) {
|
|
DeleteCallBackInterface(pCall);
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
void SetStatus(Status eNew)
|
|
{
|
|
/*
|
|
This now only manages the userWait status
|
|
*/
|
|
if(eNew == eUserWait){
|
|
userWait = 1;
|
|
} else {
|
|
if(userWait == 1){
|
|
userWait = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
void SetStatusFixed(Status eNew)
|
|
{
|
|
/* pass */
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
void ClearFixedStatus(Status eNew)
|
|
{
|
|
if (eCode == eNew) {
|
|
return;
|
|
}
|
|
eCode = eNew;
|
|
InvokeCallBack(pCall, VALUECHANGE, NULL);
|
|
fixed = 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
Status GetStatus(void)
|
|
{
|
|
return eCode;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
void GetStatusText(char *buf, int iBufLen)
|
|
{
|
|
strlcpy(buf, pText[(int) eCode], iBufLen - 1);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int SetStatusFromText(char *text)
|
|
{
|
|
int i = 0;
|
|
|
|
/* check for short form */
|
|
strtolower(text);
|
|
while (iText[i] != NULL) {
|
|
if (strcmp(text, iText[i]) == 0) {
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i >= 10) {
|
|
/* check for long form */
|
|
i = 0;
|
|
while (pText[i] != NULL) {
|
|
if (strcmp(text, pText[i]) == 0) {
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i >= 10) {
|
|
return 0;
|
|
}
|
|
}
|
|
SetStatus((Status) i);
|
|
return 1;
|
|
}
|
|
|
|
/*------------------- The CallBack function for interest ------------------*/
|
|
static int StatusCallback(int iEvent, void *pEvent, void *pUser)
|
|
{
|
|
SConnection *pCon;
|
|
char pBueffel[80];
|
|
|
|
assert(pUser);
|
|
|
|
pCon = (SConnection *) pUser;
|
|
if (pCon == NULL || !SCisConnected(pCon)) {
|
|
return -1;
|
|
}
|
|
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "status = %s", pText[(int) eCode]);
|
|
SCWrite(pCon, pBueffel, eEvent);
|
|
return 1;
|
|
}
|
|
|
|
/*------------------- The CallBack function for interest ------------------*/
|
|
static int StatusHDBCallback(int iEvent, void *pEvent, void *pUser)
|
|
{
|
|
pHdb node = NULL;
|
|
hdbValue v;
|
|
|
|
assert(pUser);
|
|
|
|
node = (pHdb) pUser;
|
|
v = MakeHdbText(pText[eCode]);
|
|
if (node != NULL && iEvent == VALUECHANGE) {
|
|
UpdateHipadabaPar(node, v, NULL);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int UserStatus(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
char pBueffel[512];
|
|
long lID;
|
|
pHdb node = NULL;
|
|
|
|
assert(pSics);
|
|
assert(pCon);
|
|
|
|
/* create callback if not present */
|
|
if (pCall == NULL) {
|
|
pCall = CreateCallBackInterface();
|
|
}
|
|
|
|
/* check for interest */
|
|
if (argc > 1) {
|
|
strtolower(argv[1]);
|
|
if (strcmp(argv[1], "interest") == 0) {
|
|
lID = RegisterCallback(pCall,
|
|
VALUECHANGE, StatusCallback,
|
|
SCCopyConnection(pCon), SCDeleteConnection);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else if (strcmp(argv[1], "hdbinterest") == 0) {
|
|
if (argc > 2) {
|
|
node = GetHipadabaNode(GetHipadabaRoot(), argv[2]);
|
|
if (node != NULL) {
|
|
lID = RegisterCallback(pCall,
|
|
VALUECHANGE, StatusHDBCallback,
|
|
node, NULL);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else {
|
|
SCWrite(pCon, "ERROR: Hipadaba node not found", eError);
|
|
return 0;
|
|
}
|
|
}
|
|
} else {
|
|
SCWrite(pCon,
|
|
"ERROR: require node parameter to register status callback",
|
|
eError);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* else just print value */
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "status = %s", pText[(int) eCode]);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int ResetStatus(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
assert(pCon);
|
|
assert(pSics);
|
|
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
SCWrite(pCon, "Insufficient authorisation to reset server", eError);
|
|
return 0;
|
|
}
|
|
// SetStatus(eEager);
|
|
eCode = eEager;
|
|
InvokeCallBack(pCall, VALUECHANGE, NULL);
|
|
SetInterrupt(eContinue);
|
|
ClearExecutor(GetExecutor());
|
|
SCsetMacro(pCon, 0);
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
Message pipe based new status calculation code
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static int DevexecStatusFunc(void *message, void *userData)
|
|
{
|
|
|
|
int *status = (int *)message;
|
|
|
|
*status = GetDevExecInstStatus(pServ->pExecutor);
|
|
return MPCONTINUE;
|
|
}
|
|
/*-----------------------------------------------------------------------------
|
|
This must be identical to the definition in interface.c As this structure is only
|
|
required in interface.c and here, I choose not to put it into an header file.
|
|
-------------------------------------------------------------------------------*/
|
|
typedef struct {
|
|
int id;
|
|
void *obj;
|
|
pICountable pCount;
|
|
SConnection *pCon;
|
|
char *name;
|
|
}CountTaskData;
|
|
/*-----------------------------------------------------------------------------*/
|
|
static int CheckCountStatus(void *message, void *userData)
|
|
{
|
|
int *status = (int *)message;
|
|
int testStatus;
|
|
pTaskHead it;
|
|
CountTaskData *countTask = NULL;
|
|
|
|
/*
|
|
This function shall never induce an interrupt
|
|
*/
|
|
SCSetInterrupt(pServ->dummyCon,eContinue);
|
|
|
|
if(*status == eCounting){
|
|
for(it = TaskIteratorStart(pServ->pTasker); it != NULL; it = TaskIteratorNext(it)){
|
|
countTask = (CountTaskData *)GetTaskData(it);
|
|
if(countTask != NULL && countTask->id == COUNTID){
|
|
testStatus = countTask->pCount->ReadStatus(countTask->obj,pServ->dummyCon);
|
|
if(testStatus == HWNoBeam){
|
|
*status = eOutOfBeam;
|
|
}
|
|
if(testStatus == HWPause){
|
|
*status = ePaused;
|
|
}
|
|
}
|
|
}
|
|
return MPSTOP;
|
|
}
|
|
return MPCONTINUE;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
static pScanData scan = NULL;
|
|
static int CheckScan(void *message, void *userData)
|
|
{
|
|
char *scannames[] = {"xxxscan","iscan", NULL};
|
|
unsigned int count = 0;
|
|
int *status = (int *)message;
|
|
|
|
if(*status == eEager){
|
|
if(scan == NULL){
|
|
while(scannames[count] != NULL){
|
|
scan = FindCommandData(pServ->pSics, scannames[count],NULL);
|
|
if(scan != NULL){
|
|
break;
|
|
}
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if(scan != NULL){
|
|
if(isScanRunning(scan)){
|
|
*status = eScanning;
|
|
return MPCONTINUE;
|
|
}
|
|
}
|
|
}
|
|
return MPCONTINUE;
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
static int CheckExe(void *message, void *userData)
|
|
{
|
|
int *status = (int *)message;
|
|
|
|
if(*status == eEager){
|
|
if(isBatchRunning()){
|
|
*status = eBatch;
|
|
}
|
|
}
|
|
return MPCONTINUE;
|
|
}
|
|
/*------------------------------------------------------------------------------*/
|
|
static int CheckUserWait(void *message, void *userData)
|
|
{
|
|
int *status = (int *)message;
|
|
|
|
if(*status == eEager){
|
|
if(isTaskRunning(pServ->pTasker,"wait")){
|
|
*status = eUserWait;
|
|
}
|
|
}
|
|
return MPCONTINUE;
|
|
}
|
|
/*--------------------------------------------------------------------------------*/
|
|
static int CheckNXScript(void *message, void *userData)
|
|
{
|
|
int *status = (int *)message;
|
|
|
|
if(*status == eEager){
|
|
if(isNXScriptWriting()){
|
|
*status = eWriting;
|
|
}
|
|
}
|
|
return MPCONTINUE;
|
|
}
|
|
/*--------------------------------------------------------------------------------*/
|
|
static pMP statusPipe = NULL;
|
|
|
|
static void BuildStatusChain(void)
|
|
{
|
|
statusPipe = MakeMP();
|
|
AppendMPFilter(statusPipe,DevexecStatusFunc,NULL,NULL);
|
|
AppendMPFilter(statusPipe,CheckCountStatus,NULL,NULL);
|
|
AppendMPFilter(statusPipe,CheckScan,NULL,NULL);
|
|
AppendMPFilter(statusPipe,CheckExe,NULL,NULL);
|
|
AppendMPFilter(statusPipe,CheckUserWait,NULL,NULL);
|
|
AppendMPFilter(statusPipe,CheckNXScript,NULL,NULL);
|
|
}
|
|
/*-------------------------------------------------------------------------------*/
|
|
static int StatusTask(void *data)
|
|
{
|
|
int status = eEager;
|
|
|
|
MPprocess(statusPipe,&status);
|
|
if(status != eCode && DoubleTime() > lastStatus + .1){
|
|
eCode = status;
|
|
lastStatus = DoubleTime();
|
|
InvokeCallBack(pCall, VALUECHANGE, NULL);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
/*---------------------------------------------------------------------------------*/
|
|
void InitStatus(void)
|
|
{
|
|
BuildStatusChain();
|
|
TaskRegisterN(pServ->pTasker,"statustask",StatusTask, NULL, NULL, NULL, TASK_PRIO_HIGH);
|
|
}
|