Files
sics/status.c
koennecke 0e2605b570 First commit towards replacing pCon-> with someFunc(pCon)
This is accompanied with the removal of dead code in conman.c and else
2016-10-31 08:33:36 +01:00

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);
}