named events

This commit is contained in:
2018-02-28 16:51:09 +01:00
parent 2772d57842
commit d2c4fd85d7
10 changed files with 219 additions and 115 deletions

View File

@@ -1415,6 +1415,10 @@ giving correct initial monitor behavior in some circumstances.</p>
<p>Fixed a crash when ALG (algorithm) was changed to Average at runtime.</p>
<h4>Named Soft Events</h4>
<p>Soft events can now be meaningful strings instead of numbers 1-255.
<h4>configure/RELEASE Enhancements</h4>
<p>Variable definitions in a <tt>configure/RELEASE</tt> file may now use the

View File

@@ -43,10 +43,11 @@
special(SPC_SCAN)
interest(1)
}
field(EVNT,DBF_SHORT) {
prompt("Event Number")
field(EVNT,DBF_STRING) {
prompt("Event Name")
promptgroup(GUI_SCAN)
special(SPC_SCAN)
size(40)
interest(1)
}
field(TSE,DBF_SHORT) {

View File

@@ -277,16 +277,26 @@ static void scanpplCallFunc(const iocshArgBuf *args)
{ scanppl(args[0].dval);}
/* scanpel */
static const iocshArg scanpelArg0 = { "event number",iocshArgInt};
static const iocshArg scanpelArg0 = { "event name",iocshArgString};
static const iocshArg * const scanpelArgs[1] = {&scanpelArg0};
static const iocshFuncDef scanpelFuncDef = {"scanpel",1,scanpelArgs};
static void scanpelCallFunc(const iocshArgBuf *args)
{ scanpel(args[0].ival);}
{ scanpel(args[0].sval);}
/* scanpiol */
static const iocshFuncDef scanpiolFuncDef = {"scanpiol",0};
static void scanpiolCallFunc(const iocshArgBuf *args) { scanpiol();}
/* postEvent */
static const iocshArg postEventArg0 = { "event name",iocshArgString};
static const iocshArg * const postEventArgs[1] = {&postEventArg0};
static const iocshFuncDef postEventFuncDef = {"postEvent",1,postEventArgs};
static void postEventCallFunc(const iocshArgBuf *args)
{
EVENTPVT pel = eventNameToHandle(args[0].sval);
postEvent(pel);
}
/* callbackSetQueueSize */
static const iocshArg callbackSetQueueSizeArg0 = { "bufsize",iocshArgInt};
static const iocshArg * const callbackSetQueueSizeArgs[1] =
@@ -340,6 +350,7 @@ void epicsShareAPI dbIocRegister(void)
iocshRegister(&scanOnceSetQueueSizeFuncDef,scanOnceSetQueueSizeCallFunc);
iocshRegister(&scanpplFuncDef,scanpplCallFunc);
iocshRegister(&scanpelFuncDef,scanpelCallFunc);
iocshRegister(&postEventFuncDef,postEventCallFunc);
iocshRegister(&scanpiolFuncDef,scanpiolCallFunc);
iocshRegister(&callbackSetQueueSizeFuncDef,callbackSetQueueSizeCallFunc);

View File

@@ -19,12 +19,14 @@
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <math.h>
#include <ctype.h>
#include "epicsStdioRedirect.h"
#include "epicsString.h"
#include "dbDefs.h"
#include "ellLib.h"
#include "taskwd.h"
#include "epicsMath.h"
#include "epicsMutex.h"
#include "epicsEvent.h"
#include "epicsExit.h"
@@ -105,13 +107,14 @@ static char *priorityName[NUM_CALLBACK_PRIORITIES] = {
/* EVENT */
#define MAX_EVENTS 256
typedef struct event_scan_list {
CALLBACK callback;
scan_list scan_list;
} event_scan_list;
static event_scan_list *pevent_list[NUM_CALLBACK_PRIORITIES][MAX_EVENTS];
typedef struct event_list {
CALLBACK callback[NUM_CALLBACK_PRIORITIES];
scan_list scan_list[NUM_CALLBACK_PRIORITIES];
struct event_list *next;
char eventname[1]; /* actually arbitrary size */
} event_list;
static event_list * volatile pevent_list[256];
static epicsMutexId event_lock;
/* IO_EVENT*/
@@ -219,35 +222,19 @@ void scanAdd(struct dbCommon *precord)
recGblRecordError(-1, (void *)precord,
"scanAdd detected illegal SCAN value");
} else if (scan == menuScanEvent) {
int evnt;
char* eventname;
int prio;
event_scan_list *pesl;
event_list *pel;
evnt = precord->evnt;
if (evnt < 0 || evnt >= MAX_EVENTS) {
recGblRecordError(S_db_badField, (void *)precord,
"scanAdd detected illegal EVNT value");
precord->scan = menuScanPassive;
return;
}
eventname = precord->evnt;
prio = precord->prio;
if (prio < 0 || prio >= NUM_CALLBACK_PRIORITIES) {
recGblRecordError(-1, (void *)precord,
"scanAdd: illegal prio field");
precord->scan = menuScanPassive;
return;
}
pesl = pevent_list[prio][evnt];
if (pesl == NULL) {
pesl = dbCalloc(1, sizeof(event_scan_list));
pevent_list[prio][evnt] = pesl;
pesl->scan_list.lock = epicsMutexMustCreate();
callbackSetCallback(eventCallback, &pesl->callback);
callbackSetPriority(prio, &pesl->callback);
callbackSetUser(pesl, &pesl->callback);
ellInit(&pesl->scan_list.list);
}
addToList(precord, &pesl->scan_list);
pel = eventNameToHandle(eventname);
if (pel) addToList(precord, &pel->scan_list[prio]);
} else if (scan == menuScanI_O_Intr) {
io_scan_list *piosl = NULL;
int prio;
@@ -304,31 +291,18 @@ void scanDelete(struct dbCommon *precord)
recGblRecordError(-1, (void *)precord,
"scanDelete detected illegal SCAN value");
} else if (scan == menuScanEvent) {
int evnt;
int prio;
event_scan_list *pesl;
event_list *pel;
scan_list *psl = 0;
evnt = precord->evnt;
if (evnt < 0 || evnt >= MAX_EVENTS) {
recGblRecordError(S_db_badField, (void *)precord,
"scanAdd detected illegal EVNT value");
precord->scan = menuScanPassive;
return;
}
prio = precord->prio;
if (prio < 0 || prio >= NUM_CALLBACK_PRIORITIES) {
recGblRecordError(-1, (void *)precord,
"scanAdd: illegal prio field");
precord->scan = menuScanPassive;
"scanDelete detected illegal PRIO field");
return;
}
pesl = pevent_list[prio][evnt];
if (pesl) psl = &pesl->scan_list;
if (!pesl || !psl)
recGblRecordError(-1, (void *)precord,
"scanDelete for bad evnt");
else
pel = eventNameToHandle(precord->evnt);
if (pel && (psl = &pel->scan_list[prio]))
deleteFromList(precord, psl);
} else if (scan == menuScanI_O_Intr) {
io_scan_list *piosl=NULL;
@@ -410,21 +384,20 @@ int scanppl(double period) /* print periodic scan list(s) */
return 0;
}
int scanpel(int event_number) /* print event list */
int scanpel(const char* eventname) /* print event list */
{
char message[80];
int prio, evnt;
event_scan_list *pesl;
for (evnt = 0; evnt < MAX_EVENTS; evnt++) {
if (event_number && evnt<event_number) continue;
if (event_number && evnt>event_number) break;
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
pesl = pevent_list[prio][evnt];
if (!pesl) continue;
if (ellCount(&pesl->scan_list.list) == 0) continue;
sprintf(message, "Event %d Priority %s", evnt, priorityName[prio]);
printList(&pesl->scan_list, message);
int prio;
event_list *pel;
for (pel = pevent_list[0]; pel; pel = pel->next) {
if (!eventname || epicsStrGlobMatch(pel->eventname, eventname)) {
printf("Event \"%s\"\n", pel->eventname);
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
if (ellCount(&pel->scan_list[prio].list) == 0) continue;
sprintf(message, " Priority %s", priorityName[prio]);
printList(&pel->scan_list[prio], message);
}
}
}
return 0;
@@ -450,39 +423,106 @@ int scanpiol(void) /* print io_event list */
static void eventCallback(CALLBACK *pcallback)
{
event_scan_list *pesl;
scan_list *psl;
callbackGetUser(pesl, pcallback);
scanList(&pesl->scan_list);
callbackGetUser(psl, pcallback);
scanList(psl);
}
static void initEvent(void)
{
int evnt, prio;
}
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
for (evnt = 0; evnt < MAX_EVENTS; evnt++) {
pevent_list[prio][evnt] = NULL;
static void eventOnce(void *arg)
{
event_lock = epicsMutexMustCreate();
}
event_list *eventNameToHandle(const char *eventname)
{
int prio;
event_list *pel;
static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
double eventnumber = 0;
size_t namelength;
char* p;
if (!eventname) return NULL;
while (isspace((unsigned char)eventname[0])) eventname++;
if (!eventname[0]) return NULL;
namelength = strlen(eventname);
while (isspace((unsigned char)eventname[namelength-1])) namelength--;
/* Backward compatibility with numeric events:
Treat any string that represents a double with an
integer part between 0 and 255 the same as the integer
because it is most probably a conversion from double
like from a calc record.
*/
eventnumber = strtod(eventname, &p);
if (*p == 0)
{
if (!finite(eventnumber))
return NULL; /* Inf and NaN are no events */
if (eventnumber >= 0 && eventnumber < 256)
{
if (eventnumber < 1)
return NULL; /* 0 is no event */
if ((pel = pevent_list[(int)eventnumber]) != NULL)
return pel;
}
else
eventnumber = 0; /* not a numeric event */
}
epicsThreadOnce(&onceId, eventOnce, NULL);
epicsMutexMustLock(event_lock);
for (pel = pevent_list[0]; pel; pel=pel->next) {
if (strncmp(pel->eventname, eventname, namelength) == 0
&& pel->eventname[namelength] == 0)
break;
}
if (pel == NULL) {
pel = dbCalloc(1, sizeof(event_list) + namelength);
if (eventnumber > 0)
{
/* backward compatibility: make all numeric events look like integers */
sprintf(pel->eventname, "%i", (int)eventnumber);
pevent_list[(int)eventnumber] = pel;
}
else
strncpy(pel->eventname, eventname, namelength);
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
callbackSetUser(&pel->scan_list[prio], &pel->callback[prio]);
callbackSetPriority(prio, &pel->callback[prio]);
callbackSetCallback(eventCallback, &pel->callback[prio]);
pel->scan_list[prio].lock = epicsMutexMustCreate();
ellInit(&pel->scan_list[prio].list);
}
pel->next=pevent_list[0];
pevent_list[0]=pel;
}
epicsMutexUnlock(event_lock);
return pel;
}
void postEvent(event_list *pel)
{
int prio;
if (scanCtl != ctlRun) return;
if (!pel) return;
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
if (ellCount(&pel->scan_list[prio].list) >0)
callbackRequest(&pel->callback[prio]);
}
}
/* backward compatibility */
void post_event(int event)
{
int prio;
event_scan_list *pesl;
if (scanCtl != ctlRun) return;
if (event < 0 || event >= MAX_EVENTS) {
errMessage(-1, "illegal event passed to post_event");
return;
}
for (prio=0; prio<NUM_CALLBACK_PRIORITIES; prio++) {
pesl = pevent_list[prio][event];
if (!pesl) continue;
if (ellCount(&pesl->scan_list.list) >0)
callbackRequest((void *)pesl);
}
if (event <= 0 || event > 255) return;
postEvent(pevent_list[event]);
}
void scanIoInit(IOSCANPVT *ppioscanpvt)

View File

@@ -31,10 +31,13 @@ extern "C" {
#define MAX_PHASE SHRT_MAX
#define MIN_PHASE SHRT_MIN
#define HAVE_NAMED_SOFT_EVENTS
/*definitions for I/O Interrupt Scanning */
struct io_scan_list;
typedef struct io_scan_list *IOSCANPVT;
typedef struct event_list *EVENTPVT;
struct dbCommon;
@@ -42,6 +45,8 @@ epicsShareFunc long scanInit(void);
epicsShareFunc void scanRun(void);
epicsShareFunc void scanPause(void);
epicsShareFunc EVENTPVT eventNameToHandle(const char* event);
epicsShareFunc void postEvent(EVENTPVT epvt);
epicsShareFunc void post_event(int event);
epicsShareFunc void scanAdd(struct dbCommon *);
epicsShareFunc void scanDelete(struct dbCommon *);
@@ -53,7 +58,7 @@ epicsShareFunc int scanOnceSetQueueSize(int size);
epicsShareFunc int scanppl(double rate);
/*print event lists*/
epicsShareFunc int scanpel(int event_number);
epicsShareFunc int scanpel(const char *event_name);
/*print io_event list*/
epicsShareFunc int scanpiol(void);

View File

@@ -50,7 +50,7 @@ static long init_record(eventRecord *prec)
/* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
switch (prec->inp.type) {
case CONSTANT:
if (recGblInitConstantLink(&prec->inp, DBF_USHORT, &prec->val))
if (recGblInitConstantLink(&prec->inp, DBF_STRING, &prec->val))
prec->udf = FALSE;
break;
case PV_LINK:
@@ -68,13 +68,20 @@ static long init_record(eventRecord *prec)
static long read_event(eventRecord *prec)
{
long status;
char newEvent[MAX_STRING_SIZE];
status = dbGetLink(&prec->inp, DBR_USHORT, &prec->val, 0, 0);
if (!status) {
prec->udf = FALSE;
if (prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
if (prec->inp.type != CONSTANT)
{
status = dbGetLinkValue(&prec->inp, DBR_STRING, newEvent, 0, 0);
if (status) return status;
if (strcmp(newEvent, prec->val) != 0) {
strcpy(prec->val, newEvent);
prec->epvt = eventNameToHandle(prec->val);
}
}
return status;
prec->udf = FALSE;
if (prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
return 0;
}

View File

@@ -197,6 +197,8 @@ static long init_record(calcoutRecord *prec, int pass)
callbackSetUser(prec, &prpvt->checkLinkCb);
prpvt->cbScheduled = 0;
prec->epvt = eventNameToHandle(prec->oevt);
if (pcalcoutDSET->init_record) pcalcoutDSET->init_record(prec);
prec->pval = prec->val;
prec->mlst = prec->val;
@@ -361,6 +363,9 @@ static long special(DBADDR *paddr, int after)
}
db_post_events(prec, plinkValid, DBE_VALUE);
return 0;
case(calcoutRecordOEVT):
prec->epvt = eventNameToHandle(prec->oevt);
return 0;
default:
recGblDbaddrError(S_db_badChoice, paddr, "calc: special");
return(S_db_badChoice);
@@ -544,27 +549,21 @@ static void execOutput(calcoutRecord *prec)
if (prec->nsev < INVALID_ALARM ) {
/* Output the value */
status = writeValue(prec);
/* post event if output event != 0 */
if (prec->oevt > 0) {
post_event((int)prec->oevt);
}
/* post output event if set */
if (prec->epvt) postEvent(prec->epvt);
} else switch (prec->ivoa) {
case menuIvoaContinue_normally:
status = writeValue(prec);
/* post event if output event != 0 */
if (prec->oevt > 0) {
post_event((int)prec->oevt);
}
/* post output event if set */
if (prec->epvt) postEvent(prec->epvt);
break;
case menuIvoaDon_t_drive_outputs:
break;
case menuIvoaSet_output_to_IVOV:
prec->oval = prec->ivov;
status = writeValue(prec);
/* post event if output event != 0 */
if (prec->oevt > 0) {
post_event((int)prec->oevt);
}
/* post output event if set */
if (prec->epvt) postEvent(prec->epvt);
break;
default:
status = -1;

View File

@@ -255,10 +255,19 @@ recordtype(calcout) {
prompt("OCAL Valid")
interest(1)
}
field(OEVT,DBF_USHORT) {
field(OEVT,DBF_STRING) {
prompt("Event To Issue")
promptgroup(GUI_CLOCK)
special(SPC_MOD)
asl(ASL0)
size(40)
}
%#include "dbScan.h"
field(EPVT, DBF_NOACCESS) {
prompt("Event private")
special(SPC_NOMOD)
interest(4)
extra("EVENTPVT epvt")
}
field(IVOA,DBF_MENU) {
prompt("INVALID output action")

View File

@@ -30,6 +30,7 @@
#include "errMdef.h"
#include "recSup.h"
#include "recGbl.h"
#include "special.h"
#include "menuYesNo.h"
#define GEN_SIZE_OFFSET
@@ -42,7 +43,7 @@
#define initialize NULL
static long init_record(eventRecord *, int);
static long process(eventRecord *);
#define special NULL
static long special(DBADDR *, int);
static long get_value(eventRecord *, struct valueDes *);
#define cvt_dbaddr NULL
#define get_array_info NULL
@@ -102,9 +103,11 @@ static long init_record(eventRecord *prec, int pass)
}
if (prec->siol.type == CONSTANT) {
recGblInitConstantLink(&prec->siol,DBF_USHORT,&prec->sval);
recGblInitConstantLink(&prec->siol,DBF_STRING,&prec->sval);
}
prec->epvt = eventNameToHandle(prec->val);
if( (pdset=(struct eventdset *)(prec->dset)) && (pdset->init_record) )
status=(*pdset->init_record)(prec);
return(status);
@@ -122,7 +125,7 @@ static long process(eventRecord *prec)
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
if(prec->val>0) post_event((int)prec->val);
postEvent(prec->epvt);
recGblGetTimeStamp(prec);
@@ -136,10 +139,22 @@ static long process(eventRecord *prec)
return(status);
}
static long special(DBADDR *paddr, int after)
{
eventRecord *prec = (eventRecord *)paddr->precord;
if (!after) return 0;
if (dbGetFieldIndex(paddr) == eventRecordVAL) {
prec->epvt = eventNameToHandle(prec->val);
}
return 0;
}
static long get_value(eventRecord *prec, struct valueDes *pvdes)
{
pvdes->field_type = DBF_USHORT;
pvdes->field_type = DBF_STRING;
pvdes->no_elements=1;
pvdes->pvalue = (void *)(&prec->val);
return(0);
@@ -176,10 +191,13 @@ static long readValue(eventRecord *prec)
return(status);
}
if (prec->simm == menuYesNoYES){
status=dbGetLink(&(prec->siol),DBR_USHORT,
status=dbGetLink(&(prec->siol),DBR_STRING,
&(prec->sval),0,0);
if (status==0) {
prec->val=prec->sval;
if (strcmp(prec->sval, prec->val) != 0) {
strcpy(prec->val, prec->sval);
prec->epvt = eventNameToHandle(prec->val);
}
prec->udf=FALSE;
}
} else {

View File

@@ -9,10 +9,19 @@
#*************************************************************************
recordtype(event) {
include "dbCommon.dbd"
field(VAL,DBF_USHORT) {
prompt("Event Number To Post")
field(VAL,DBF_STRING) {
prompt("Event Name To Post")
promptgroup(GUI_INPUTS)
special(SPC_MOD)
asl(ASL0)
size(40)
}
%#include "dbScan.h"
field(EPVT, DBF_NOACCESS) {
prompt("Event private")
special(SPC_NOMOD)
interest(4)
extra("EVENTPVT epvt")
}
field(INP,DBF_INLINK) {
prompt("Input Specification")
@@ -24,8 +33,9 @@ recordtype(event) {
promptgroup(GUI_INPUTS)
interest(1)
}
field(SVAL,DBF_USHORT) {
field(SVAL,DBF_STRING) {
prompt("Simulation Value")
size(40)
}
field(SIML,DBF_INLINK) {
prompt("Sim Mode Location")