Merge tag 'R7.0.6' into PSI-7.0

ANJ: Tagged for release

Conflicts:
	.ci
	configure/os/CONFIG_SITE.linux-x86.Common
	modules/libcom/src/misc/epicsString.h
	src/tools/makeTestfile.pl
This commit is contained in:
2021-07-08 19:00:08 +02:00
211 changed files with 4486 additions and 1645 deletions
+22 -2
View File
@@ -360,6 +360,16 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options,
*pushort++ = pcommon->ackt;
pbuffer = (char *)pushort;
}
if( (*options) & DBR_AMSG ) {
if (!pfl) {
STATIC_ASSERT(sizeof(pcommon->amsg)==sizeof(pfl->amsg));
strncpy(pbuffer, pcommon->amsg, sizeof(pcommon->amsg)-1);
} else {
strncpy(pbuffer, pfl->amsg,sizeof(pfl->amsg)-1);
}
pbuffer[sizeof(pcommon->amsg)-1] = '\0';
pbuffer += sizeof(pcommon->amsg);
}
if( (*options) & DBR_UNITS ) {
memset(pbuffer,'\0',dbr_units_size);
if( prset && prset->get_units ){
@@ -392,6 +402,15 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options,
}
pbuffer = (char *)ptime;
}
if( (*options) & DBR_UTAG ) {
epicsUInt64 *ptag = (epicsUInt64*)pbuffer;
if (!pfl) {
*ptag++ = pcommon->utag;
} else {
*ptag++ = pfl->utag;
}
pbuffer = (char *)ptag;
}
if( (*options) & DBR_ENUM_STRS )
get_enum_strs(paddr, &pbuffer, prset, options);
if( (*options) & (DBR_GR_LONG|DBR_GR_DOUBLE ))
@@ -523,7 +542,7 @@ long dbProcess(dbCommon *precord)
(precord->lcnt++ < MAX_LOCK) ||
(precord->sevr >= INVALID_ALARM)) goto all_done;
recGblSetSevr(precord, SCAN_ALARM, INVALID_ALARM);
recGblSetSevrMsg(precord, SCAN_ALARM, INVALID_ALARM, "Async in progress");
monitor_mask = recGblResetAlarms(precord);
monitor_mask |= DBE_VALUE|DBE_LOG;
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes];
@@ -1385,7 +1404,8 @@ long dbPut(DBADDR *paddr, short dbrType,
/* Always do special processing if needed */
if (special) {
long status2 = dbPutSpecial(paddr, 1);
if (status2) goto done;
if (status2)
status = status2;
}
if (status) goto done;
+18 -11
View File
@@ -33,16 +33,18 @@ DBCORE_API extern int dbAccessDebugPUTF;
/* The database field and request types are defined in dbFldTypes.h*/
/* Data Base Request Options */
#define DBR_STATUS 0x00000001
#define DBR_UNITS 0x00000002
#define DBR_PRECISION 0x00000004
#define DBR_TIME 0x00000008
#define DBR_ENUM_STRS 0x00000010
#define DBR_GR_LONG 0x00000020
#define DBR_GR_DOUBLE 0x00000040
#define DBR_CTRL_LONG 0x00000080
#define DBR_CTRL_DOUBLE 0x00000100
#define DBR_AL_LONG 0x00000200
#define DBR_AL_DOUBLE 0x00000400
#define DBR_AMSG 0x00000002
#define DBR_UNITS 0x00000004
#define DBR_PRECISION 0x00000008
#define DBR_TIME 0x00000010
#define DBR_UTAG 0x00000020
#define DBR_ENUM_STRS 0x00000040
#define DBR_GR_LONG 0x00000080
#define DBR_GR_DOUBLE 0x00000100
#define DBR_CTRL_LONG 0x00000200
#define DBR_CTRL_DOUBLE 0x00000400
#define DBR_AL_LONG 0x00000800
#define DBR_AL_DOUBLE 0x00001000
/**********************************************************************
* The next page contains macros for defining requests.
@@ -100,6 +102,9 @@ DBCORE_API extern int dbAccessDebugPUTF;
epicsUInt16 severity; /* alarm severity*/\
epicsUInt16 acks; /* alarm ack severity*/\
epicsUInt16 ackt; /* Acknowledge transient alarms?*/
#define DB_AMSG_SIZE 40
#define DBRamsg \
char amsg[DB_AMSG_SIZE];
#define DB_UNITS_SIZE 16
#define DBRunits \
char units[DB_UNITS_SIZE]; /* units */
@@ -112,7 +117,9 @@ DBCORE_API extern int dbAccessDebugPUTF;
* too late to change now. DBRprecision must be padded to
* maintain 8-byte alignment. */
#define DBRtime \
epicsTimeStamp time; /* time stamp*/
epicsTimeStamp time; /* time stamp*/
#define DBRutag \
epicsUTag utag;
#define DBRenumStrs \
epicsUInt32 no_str; /* number of strings*/\
epicsInt32 padenumStrs; /*padding to force 8 byte align*/\
@@ -279,6 +279,11 @@ support routines which write to the VAL field are responsible for setting UDF.
special(SPC_NOMOD)
menu(menuAlarmSevr)
}
field(AMSG,DBF_STRING) {
prompt("Alarm Message")
special(SPC_NOMOD)
size(40)
}
field(NSTA,DBF_MENU) {
prompt("New Alarm Status")
special(SPC_NOMOD)
@@ -291,6 +296,11 @@ support routines which write to the VAL field are responsible for setting UDF.
interest(2)
menu(menuAlarmSevr)
}
field(NAMSG,DBF_STRING) {
prompt("New Alarm Message")
special(SPC_NOMOD)
size(40)
}
field(ACKS,DBF_MENU) {
prompt("Alarm Ack Severity")
special(SPC_NOMOD)
@@ -514,6 +524,11 @@ field which is then used to acquire a timestamp.
interest(2)
extra("epicsTimeStamp time")
}
field(UTAG,DBF_UINT64) {
prompt("Time Tag")
special(SPC_NOMOD)
interest(3)
}
field(FLNK,DBF_FWDLINK) {
prompt("Forward Process Link")
promptgroup("20 - Scan")
+13 -5
View File
@@ -337,8 +337,8 @@ static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
return 0;
}
static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity)
static long dbDbGetAlarmMsg(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity, char *msgbuf, size_t msgbuflen)
{
dbChannel *chan = linkChannel(plink);
dbCommon *precord = dbChannelRecord(chan);
@@ -346,14 +346,20 @@ static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status,
*status = precord->stat;
if (severity)
*severity = precord->sevr;
if (msgbuf && msgbuflen) {
strncpy(msgbuf, precord->amsg, msgbuflen-1);
msgbuf[msgbuflen-1] = '\0';
}
return 0;
}
static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
static long dbDbGetTimeStampTag(const struct link *plink, epicsTimeStamp *pstamp, epicsUTag *ptag)
{
dbChannel *chan = linkChannel(plink);
dbCommon *precord = dbChannelRecord(chan);
*pstamp = precord->time;
if(ptag)
*ptag = precord->utag;
return 0;
}
@@ -401,9 +407,11 @@ static lset dbDb_lset = {
dbDbGetValue,
dbDbGetControlLimits, dbDbGetGraphicLimits, dbDbGetAlarmLimits,
dbDbGetPrecision, dbDbGetUnits,
dbDbGetAlarm, dbDbGetTimeStamp,
NULL, NULL,
dbDbPutValue, NULL,
dbDbScanFwdLink, doLocked
dbDbScanFwdLink, doLocked,
dbDbGetAlarmMsg,
dbDbGetTimeStampTag,
};
+51 -16
View File
@@ -84,6 +84,7 @@ struct event_user {
epicsMutexId lock;
epicsEventId ppendsem; /* Wait while empty */
epicsEventId pflush_sem; /* wait for flush */
epicsEventId pexitsem; /* wait for event task to join */
EXTRALABORFUNC *extralabor_sub;/* off load to event task */
void *extralabor_arg;/* parameter to above */
@@ -122,6 +123,8 @@ static char *EVENT_PEND_NAME = "eventTask";
static struct evSubscrip canceledEvent;
static epicsMutexId stopSync;
static unsigned short ringSpace ( const struct event_que *pevq )
{
if ( pevq->evque[pevq->putix] == EVENTQEMPTY ) {
@@ -260,6 +263,10 @@ int dbel ( const char *pname, unsigned level )
*/
void db_init_event_freelists (void)
{
if (!stopSync) {
stopSync = epicsMutexMustCreate();
}
if (!dbevEventUserFreeList) {
freeListInitPvt(&dbevEventUserFreeList,
sizeof(struct event_user),8);
@@ -299,6 +306,9 @@ dbEventCtx db_init_events (void)
return NULL;
}
/* Flag will be cleared when event task starts */
evUser->pendexit = TRUE;
evUser->firstque.evUser = evUser;
evUser->firstque.writelock = epicsMutexCreate();
if (!evUser->firstque.writelock)
@@ -313,6 +323,9 @@ dbEventCtx db_init_events (void)
evUser->lock = epicsMutexCreate();
if (!evUser->lock)
goto fail;
evUser->pexitsem = epicsEventCreate(epicsEventEmpty);
if (!evUser->pexitsem)
goto fail;
evUser->flowCtrlMode = FALSE;
evUser->extraLaborBusy = FALSE;
@@ -327,6 +340,8 @@ fail:
epicsEventDestroy (evUser->ppendsem);
if(evUser->pflush_sem)
epicsEventDestroy (evUser->pflush_sem);
if(evUser->pexitsem)
epicsEventDestroy (evUser->pexitsem);
freeListFree(dbevEventUserFreeList,evUser);
return NULL;
}
@@ -347,6 +362,7 @@ DBCORE_API void db_cleanup_events(void)
dbevFieldLogFreeList = NULL;
}
/* intentionally leak stopSync to avoid possible shutdown races */
/*
* DB_CLOSE_EVENTS()
*
@@ -368,15 +384,31 @@ void db_close_events (dbEventCtx ctx)
* hazardous to the system's health.
*/
epicsMutexMustLock ( evUser->lock );
evUser->pendexit = TRUE;
if(!evUser->pendexit) { /* event task running */
evUser->pendexit = TRUE;
epicsMutexUnlock ( evUser->lock );
/* notify the waiting task */
epicsEventSignal(evUser->ppendsem);
/* wait for task to exit */
epicsEventMustWait(evUser->pexitsem);
epicsThreadMustJoin(evUser->taskid);
epicsMutexMustLock ( evUser->lock );
}
epicsMutexUnlock ( evUser->lock );
/* notify the waiting task */
epicsEventSignal(evUser->ppendsem);
epicsMutexMustLock (stopSync);
if(evUser->taskid)
epicsThreadMustJoin(evUser->taskid);
/* evUser has been deleted by the worker */
epicsEventDestroy(evUser->pexitsem);
epicsEventDestroy(evUser->ppendsem);
epicsEventDestroy(evUser->pflush_sem);
epicsMutexDestroy(evUser->lock);
epicsMutexUnlock (stopSync);
freeListFree(dbevEventUserFreeList, evUser);
}
/*
@@ -675,7 +707,10 @@ static db_field_log* db_create_field_log (struct dbChannel *chan, int use_val)
struct dbCommon *prec = dbChannelRecord(chan);
pLog->stat = prec->stat;
pLog->sevr = prec->sevr;
strncpy(pLog->amsg, prec->amsg, sizeof(pLog->amsg)-1);
pLog->amsg[sizeof(pLog->amsg)-1] = '\0';
pLog->time = prec->time;
pLog->utag = prec->utag;
pLog->field_type = dbChannelFieldType(chan);
pLog->field_size = dbChannelFieldSize(chan);
pLog->no_elements = dbChannelElements(chan);
@@ -1060,18 +1095,17 @@ static void event_task (void *pParm)
}
}
epicsEventDestroy(evUser->ppendsem);
epicsEventDestroy(evUser->pflush_sem);
epicsMutexDestroy(evUser->lock);
if (dbevEventUserFreeList)
freeListFree(dbevEventUserFreeList, evUser);
else
fprintf(stderr, "%s exiting but dbevEventUserFreeList already NULL\n",
__FUNCTION__);
taskwdRemove(epicsThreadGetIdSelf());
/* use stopSync to ensure pexitsem is not destroy'd
* until epicsEventSignal() has returned.
*/
epicsMutexMustLock (stopSync);
epicsEventSignal(evUser->pexitsem);
epicsMutexUnlock(stopSync);
return;
}
@@ -1111,6 +1145,7 @@ int db_start_events (
epicsMutexUnlock ( evUser->lock );
return DB_EVENT_ERROR;
}
evUser->pendexit = FALSE;
epicsMutexUnlock ( evUser->lock );
return DB_EVENT_OK;
}
+35 -15
View File
@@ -313,10 +313,16 @@ long dbTryGetLink(struct link *plink, short dbrType, void *pbuffer,
return plset->getValue(plink, dbrType, pbuffer, pnRequest);
}
static
void setLinkAlarm(struct link* plink)
{
recGblSetSevrMsg(plink->precord, LINK_ALARM, INVALID_ALARM,
"field %s", dbLinkFieldName(plink));
}
long dbGetLink(struct link *plink, short dbrType, void *pbuffer,
long *poptions, long *pnRequest)
{
struct dbCommon *precord = plink->precord;
long status;
if (poptions && *poptions) {
@@ -328,7 +334,7 @@ long dbGetLink(struct link *plink, short dbrType, void *pbuffer,
if (status == S_db_noLSET)
return -1;
if (status)
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
setLinkAlarm(plink);
return status;
}
@@ -385,24 +391,42 @@ long dbGetUnits(const struct link *plink, char *units, int unitsSize)
}
long dbGetAlarm(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity)
epicsEnum16 *severity)
{
return dbGetAlarmMsg(plink, status, severity, NULL, 0);
}
long dbGetAlarmMsg(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity, char *msgbuf, size_t msgbuflen)
{
lset *plset = plink->lset;
if (!plset || !plset->getAlarm)
if (plset && plset->getAlarmMsg) {
return plset->getAlarmMsg(plink, status, severity, msgbuf, msgbuflen);
} else if(plset && plset->getAlarm) {
return plset->getAlarm(plink, status, severity);
} else {
return S_db_noLSET;
return plset->getAlarm(plink, status, severity);
}
}
long dbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
{
return dbGetTimeStampTag(plink, pstamp, NULL);
}
long dbGetTimeStampTag(const struct link *plink,
epicsTimeStamp *pstamp, epicsUTag *ptag)
{
lset *plset = plink->lset;
if (!plset || !plset->getTimeStamp)
if (plset && plset->getTimeStampTag) {
return plset->getTimeStampTag(plink, pstamp, ptag);
} else if(plset && plset->getTimeStamp) {
return plset->getTimeStamp(plink, pstamp);
} else {
return S_db_noLSET;
return plset->getTimeStamp(plink, pstamp);
}
}
long dbPutLink(struct link *plink, short dbrType, const void *pbuffer,
@@ -416,9 +440,7 @@ long dbPutLink(struct link *plink, short dbrType, const void *pbuffer,
status = plset->putValue(plink, dbrType, pbuffer, nRequest);
if (status) {
struct dbCommon *precord = plink->precord;
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
setLinkAlarm(plink);
}
return status;
}
@@ -443,9 +465,7 @@ long dbPutLinkAsync(struct link *plink, short dbrType, const void *pbuffer,
status = plset->putAsync(plink, dbrType, pbuffer, nRequest);
if (status) {
struct dbCommon *precord = plink->precord;
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
setLinkAlarm(plink);
}
return status;
}
+35
View File
@@ -361,6 +361,29 @@ typedef struct lset {
* @returns status value
*/
long (*doLocked)(struct link *plink, dbLinkUserCallback rtn, void *priv);
/** @brief Extended version of getAlarm
*
* Equivalent of getAlarm() and also copy out alarm message string.
* The msgbuf argument may be NULL and/or msgbuflen==0, in which case
* the effect must be the same as a call to getAlarm().
*
* Implementations must write a trailing nil to msgbuf whenever
* @code msgbuf!=NULL && msgbuflen>0 @endcode .
*
* @since 7.0.6
*/
long (*getAlarmMsg)(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity, char *msgbuf, size_t msgbuflen);
/** @brief Extended version of getTimeStamp
*
* Equivalent of getTimeStamp() and also copy out time tag.
* ptag may be NULL.
*
* @since Added after 7.0.6
*/
long (*getTimeStampTag)(const struct link *plink, epicsTimeStamp *pstamp, epicsUTag *ptag);
} lset;
#define dbGetSevr(link, sevr) \
@@ -402,8 +425,20 @@ DBCORE_API long dbGetUnits(const struct link *plink, char *units,
int unitsSize);
DBCORE_API long dbGetAlarm(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity);
/** Get link alarm and message string.
* To ensure the complete message string is copied, ensure @code msgbuflen >= sizeof (dbCommon::amsg) @endcode .
* A trailing nil will be added whenever @code msgbuflen > 0 @endcode .
* @since 7.0.6
*/
DBCORE_API long dbGetAlarmMsg(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity, char *msgbuf, size_t msgbuflen);
#define dbGetAlarmMsg(LINK, STAT, SEVR, BUF, BUFLEN) dbGetAlarmMsg(LINK, STAT, SEVR, BUF, BUFLEN)
DBCORE_API long dbGetTimeStamp(const struct link *plink,
epicsTimeStamp *pstamp);
/** @since 7.0.6 */
DBCORE_API long dbGetTimeStampTag(const struct link *plink,
epicsTimeStamp *pstamp, epicsUTag *ptag);
#define dbGetTimeStampTag(LINK, STAMP, TAG) dbGetTimeStampTag(LINK, STAMP, TAG)
DBCORE_API long dbPutLink(struct link *plink, short dbrType,
const void *pbuffer, long nRequest);
DBCORE_API void dbLinkAsyncComplete(struct link *plink);
+2 -2
View File
@@ -266,7 +266,7 @@ done:
void testdbPutArrFieldOk(const char* pv, short dbrType, unsigned long count, const void *pbuf)
{
dbChannel *chan = dbChannelCreate(pv);
long status;
long status = -1;
if(!chan || (status=dbChannelOpen(chan))) {
testFail("Channel error (%p, %ld) : %s", chan, status, pv);
@@ -289,7 +289,7 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign
const long vSize = dbValueSize(dbfType);
const long nStore = vSize * nRequest;
long status = S_dbLib_recNotFound;
char *gbuf, *gstore;
char *gbuf, *gstore = NULL;
const char *pbuf = pbufraw;
if(!chan || (status=dbChannelOpen(chan))) {
@@ -113,8 +113,10 @@ typedef struct db_field_log {
unsigned char mask; /* DBE_* mask */
/* the following are used for value and reference types */
epicsTimeStamp time; /* Time stamp */
epicsUTag utag;
unsigned short stat; /* Alarm Status */
unsigned short sevr; /* Alarm Severity */
char amsg[40];
short field_type; /* DBF type of data */
short field_size; /* Size of a single element */
long no_elements; /* No of valid array elements */
+35 -2
View File
@@ -24,6 +24,7 @@
#include "epicsMath.h"
#include "epicsPrint.h"
#include "epicsStdlib.h"
#include "epicsStdio.h"
#include "epicsTime.h"
#include "errlog.h"
@@ -184,6 +185,11 @@ unsigned short recGblResetAlarms(void *precord)
if (new_sevr > INVALID_ALARM)
new_sevr = INVALID_ALARM;
if(strcmp(pdbc->namsg, pdbc->amsg)!=0) {
strcpy(pdbc->amsg, pdbc->namsg);
stat_mask = DBE_ALARM;
}
pdbc->stat = new_stat;
pdbc->sevr = new_sevr;
pdbc->nsta = 0;
@@ -198,6 +204,7 @@ unsigned short recGblResetAlarms(void *precord)
}
if (stat_mask) {
db_post_events(pdbc, &pdbc->stat, stat_mask);
db_post_events(pdbc, &pdbc->amsg, stat_mask);
val_mask = DBE_ALARM;
if (!pdbc->ackt || new_sevr >= pdbc->acks) {
@@ -211,18 +218,44 @@ unsigned short recGblResetAlarms(void *precord)
}
return val_mask;
}
int recGblSetSevrMsg(void *precord, epicsEnum16 new_stat,
epicsEnum16 new_sevr,
const char *msg, ...)
{
int ret;
va_list args;
va_start(args, msg);
ret = recGblSetSevrVMsg(precord, new_stat, new_sevr, msg, args);
va_end(args);
return ret;
}
int recGblSetSevr(void *precord, epicsEnum16 new_stat, epicsEnum16 new_sevr)
int recGblSetSevrVMsg(void *precord, epicsEnum16 new_stat,
epicsEnum16 new_sevr,
const char *msg, va_list args)
{
struct dbCommon *prec = precord;
if (prec->nsev < new_sevr) {
prec->nsta = new_stat;
prec->nsev = new_sevr;
if(msg) {
epicsVsnprintf(prec->namsg, sizeof(prec->namsg)-1, msg, args);
prec->namsg[sizeof(prec->namsg)-1] = '\0';
} else {
prec->namsg[0] = '\0';
}
prec->namsg[sizeof(prec->namsg)-1] = '\0';
return TRUE;
}
return FALSE;
}
int recGblSetSevr(void *precord, epicsEnum16 new_stat, epicsEnum16 new_sevr)
{
return recGblSetSevrMsg(precord, new_stat, new_sevr, NULL);
}
void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat,
epicsEnum16 sevr)
{
@@ -271,7 +304,7 @@ void recGblGetTimeStampSimm(void *pvoid, const epicsEnum16 simm, struct link *si
if (!dbLinkIsConstant(plink)) {
if (plink->flags & DBLINK_FLAG_TSELisTIME) {
if (dbGetTimeStamp(plink, &prec->time))
if (dbGetTimeStampTag(plink, &prec->time, &prec->utag))
errlogPrintf("recGblGetTimeStamp: dbGetTimeStamp failed for %s.TSEL\n",
prec->name);
return;
+17
View File
@@ -15,6 +15,9 @@
#ifndef INCrecGblh
#define INCrecGblh 1
#include <stdarg.h>
#include "compilerDependencies.h"
#include "epicsTypes.h"
#include "dbCoreAPI.h"
@@ -22,6 +25,14 @@
extern "C" {
#endif
/** Feature test macro for alarm message (AMSG) field and support
*
* Covers addition of dbCommon::amsg, recGblSetSevrMsg(), lset::getAlarmMsg()
*
* @since 7.0.6
*/
#define HAS_ALARM_MESSAGE 1
/*************************************************************************/
/* Structures needed for args */
@@ -62,6 +73,12 @@ DBCORE_API int recGblSetSevr(void *precord, epicsEnum16 new_stat,
epicsEnum16 new_sevr);
DBCORE_API void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat,
epicsEnum16 sevr);
DBCORE_API int recGblSetSevrMsg(void *precord, epicsEnum16 new_stat,
epicsEnum16 new_sevr,
const char *msg, ...) EPICS_PRINTF_STYLE(4,5);
DBCORE_API int recGblSetSevrVMsg(void *precord, epicsEnum16 new_stat,
epicsEnum16 new_sevr,
const char *msg, va_list args);
DBCORE_API void recGblFwdLink(void *precord);
DBCORE_API void recGblGetTimeStamp(void *precord);
DBCORE_API void recGblGetTimeStampSimm(void *prec, const epicsEnum16 simm, struct link *siol);
+2 -2
View File
@@ -63,7 +63,7 @@ static long read_lsi(lsiRecord *prec)
prec->val[0] = 0;
prec->len = 1;
prec->udf = TRUE;
recGblSetSevr(prec, UDF_ALARM, prec->udfs);
recGblSetSevrMsg(prec, UDF_ALARM, prec->udfs, "No such ENV");
}
return 0;
@@ -114,7 +114,7 @@ static long read_stringin(stringinRecord *prec)
else {
prec->val[0] = 0;
prec->udf = TRUE;
recGblSetSevr(prec, UDF_ALARM, prec->udfs);
recGblSetSevrMsg(prec, UDF_ALARM, prec->udfs, "No such ENV");
}
return 0;
@@ -16,6 +16,7 @@ dbRecStd_SRCS += dbnd.c
dbRecStd_SRCS += arr.c
dbRecStd_SRCS += sync.c
dbRecStd_SRCS += decimate.c
dbRecStd_SRCS += utag.c
HTMLS += filters.html
@@ -16,6 +16,8 @@ The following filters are available in this release:
=item * L<Decimation|/"Decimation Filter dec">
=item * L<UTag|/"UTag Filter utag">
=back
=head2 Using Filters
@@ -285,3 +287,26 @@ once every minute:
...
=cut
registrar(utagInitialize)
=head3 UTag Filter C<"utag">
This filter applies a test UTAG&M==V to the value taken from the UTAG record field
and drops those updates which evaluate as false.
=head4 Parameters
=over
=item Mask C<"M">
Bit mask.
=item Value C<"V">
Required value.
=back
=cut
+99
View File
@@ -0,0 +1,99 @@
/*************************************************************************\
* Copyright (c) 2020 Michael Davidsaver
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <stdlib.h>
#include <caeventmask.h>
#include <chfPlugin.h>
#include <dbCommon.h>
#include <epicsStdio.h>
#include <epicsExport.h>
typedef struct {
epicsInt32 mask, value;
int first;
} utagPvt;
static const
chfPluginArgDef opts[] = {
chfInt32(utagPvt, mask, "M", 0, 1),
chfInt32(utagPvt, value, "V", 0, 1),
chfPluginArgEnd
};
static void * allocPvt(void)
{
utagPvt *pvt;
pvt = calloc(1, sizeof(utagPvt));
pvt->mask = 0xffffffff;
return pvt;
}
static void freePvt(void *pvt)
{
free(pvt);
}
static int parse_ok(void *raw)
{
utagPvt *pvt = (utagPvt*)raw;
pvt->first = 1;
return 0;
}
static db_field_log* filter(void* raw, dbChannel *chan, db_field_log *pfl)
{
utagPvt *pvt = (utagPvt*)raw;
epicsUTag utag = pfl->utag;
int drop = (utag&pvt->mask)!=pvt->value;
if(pfl->ctx!=dbfl_context_event || pfl->mask&DBE_PROPERTY) {
/* never drop for reads, or property events */
} else if(pvt->first) {
/* never drop first */
pvt->first = 0;
} else if(drop) {
db_delete_field_log(pfl);
pfl = NULL;
}
return pfl;
}
static void channelRegisterPre(dbChannel *chan, void *pvt,
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
{
*cb_out = filter;
*arg_out = pvt;
}
static void channel_report(dbChannel *chan, void *raw, int level, const unsigned short indent)
{
utagPvt *pvt = (utagPvt*)raw;
printf("%*sutag : mask=0x%08x value=0x%08x\n", indent, "", (epicsUInt32)pvt->mask, (epicsUInt32)pvt->value);
}
static const
chfPluginIf pif = {
allocPvt,
freePvt,
NULL, /* parse_error */
parse_ok, /* parse_ok */
NULL, /* channel_open */
channelRegisterPre,
NULL, /* channelRegisterPost */
channel_report,
NULL, /* channel_close */
};
static
void utagInitialize(void)
{
chfPluginRegister("utag", &pif, opts);
}
epicsExportRegistrar(utagInitialize);
+34 -14
View File
@@ -53,6 +53,7 @@ typedef struct calc_link {
} pstate;
epicsEnum16 stat;
epicsEnum16 sevr;
char amsg[DB_AMSG_SIZE];
short prec;
char *expr;
char *major;
@@ -66,6 +67,7 @@ typedef struct calc_link {
struct link out;
double arg[CALCPERFORM_NARGS];
epicsTimeStamp time;
epicsUTag utag;
double val;
} calc_link;
@@ -385,9 +387,10 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent)
if (level > 0) {
if (clink->sevr)
printf("%*s Alarm: %s, %s\n", indent, "",
printf("%*s Alarm: %s, %s, \"%s\"\n", indent, "",
epicsAlarmSeverityStrings[clink->sevr],
epicsAlarmConditionStrings[clink->stat]);
epicsAlarmConditionStrings[clink->stat],
clink->amsg);
if (clink->post_major)
printf("%*s Major expression: \"%s\"\n", indent, "",
@@ -532,6 +535,7 @@ static long lnkCalc_getElements(const struct link *plink, long *nelements)
struct lcvt {
double *pval;
epicsTimeStamp *ptime;
epicsUTag *ptag;
};
static long readLocked(struct link *pinp, void *vvt)
@@ -541,7 +545,7 @@ static long readLocked(struct link *pinp, void *vvt)
long status = dbGetLink(pinp, DBR_DOUBLE, pvt->pval, NULL, &nReq);
if (!status && pvt->ptime)
dbGetTimeStamp(pinp, pvt->ptime);
dbGetTimeStampTag(pinp, pvt->ptime, pvt->ptag);
return status;
}
@@ -567,7 +571,7 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
long nReq = 1;
if (i == clink->tinp) {
struct lcvt vt = {&clink->arg[i], &clink->time};
struct lcvt vt = {&clink->arg[i], &clink->time, &clink->utag};
status = dbLinkDoLocked(child, readLocked, &vt);
if (status == S_db_noLSET)
@@ -576,6 +580,7 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime) {
prec->time = clink->time;
prec->utag = clink->utag;
}
}
else
@@ -583,6 +588,7 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
}
clink->stat = 0;
clink->sevr = 0;
clink->amsg[0] = '\0';
if (clink->post_expr) {
status = calcPerform(clink->arg, &clink->val, clink->post_expr);
@@ -604,7 +610,8 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
if (!status && alval) {
clink->stat = LINK_ALARM;
clink->sevr = MAJOR_ALARM;
recGblSetSevr(prec, clink->stat, clink->sevr);
strcpy(clink->amsg, "post_major error");
recGblSetSevrMsg(prec, clink->stat, clink->sevr, "post_major error");
}
}
@@ -615,7 +622,8 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
if (!status && alval) {
clink->stat = LINK_ALARM;
clink->sevr = MINOR_ALARM;
recGblSetSevr(prec, clink->stat, clink->sevr);
strcpy(clink->amsg, "post_minor error");
recGblSetSevrMsg(prec, clink->stat, clink->sevr, "post_minor error");
}
}
@@ -643,7 +651,7 @@ static long lnkCalc_putValue(struct link *plink, short dbrType,
long nReq = 1;
if (i == clink->tinp) {
struct lcvt vt = {&clink->arg[i], &clink->time};
struct lcvt vt = {&clink->arg[i], &clink->time, &clink->utag};
status = dbLinkDoLocked(child, readLocked, &vt);
if (status == S_db_noLSET)
@@ -652,6 +660,7 @@ static long lnkCalc_putValue(struct link *plink, short dbrType,
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime) {
prec->time = clink->time;
prec->utag = clink->utag;
}
}
else
@@ -659,6 +668,7 @@ static long lnkCalc_putValue(struct link *plink, short dbrType,
}
clink->stat = 0;
clink->sevr = 0;
clink->amsg[0] = '\0';
/* Get the value being output as VAL */
status = conv(pbuffer, &clink->val, NULL);
@@ -673,7 +683,8 @@ static long lnkCalc_putValue(struct link *plink, short dbrType,
if (!status && alval) {
clink->stat = LINK_ALARM;
clink->sevr = MAJOR_ALARM;
recGblSetSevr(prec, clink->stat, clink->sevr);
strcpy(clink->amsg, "post_major error");
recGblSetSevrMsg(prec, clink->stat, clink->sevr, "post_major error");
}
}
@@ -684,7 +695,8 @@ static long lnkCalc_putValue(struct link *plink, short dbrType,
if (!status && alval) {
clink->stat = LINK_ALARM;
clink->sevr = MINOR_ALARM;
recGblSetSevr(prec, clink->stat, clink->sevr);
strcpy(clink->amsg, "post_major error");
recGblSetSevrMsg(prec, clink->stat, clink->sevr, "post_minor error");
}
}
@@ -718,8 +730,8 @@ static long lnkCalc_getUnits(const struct link *plink, char *units, int len)
return 0;
}
static long lnkCalc_getAlarm(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity)
static long lnkCalc_getAlarmMsg(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity, char *msgbuf, size_t msgbuflen)
{
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
@@ -728,17 +740,23 @@ static long lnkCalc_getAlarm(const struct link *plink, epicsEnum16 *status,
*status = clink->stat;
if (severity)
*severity = clink->sevr;
if (msgbuf && msgbuflen) {
strncpy(msgbuf, clink->amsg, msgbuflen-1);
msgbuf[msgbuflen-1] = '\0';
}
return 0;
}
static long lnkCalc_getTimestamp(const struct link *plink, epicsTimeStamp *pstamp)
static long lnkCalc_getTimestampTag(const struct link *plink, epicsTimeStamp *pstamp, epicsUTag *ptag)
{
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
if (clink->tinp >= 0) {
*pstamp = clink->time;
if(ptag)
*ptag = clink->utag;
return 0;
}
@@ -761,9 +779,11 @@ static lset lnkCalc_lset = {
lnkCalc_getValue,
NULL, NULL, NULL,
lnkCalc_getPrecision, lnkCalc_getUnits,
lnkCalc_getAlarm, lnkCalc_getTimestamp,
NULL, NULL,
lnkCalc_putValue, NULL,
NULL, doLocked
NULL, doLocked,
lnkCalc_getAlarmMsg,
lnkCalc_getTimestampTag,
};
static jlif lnkCalcIf = {
+1 -1
View File
@@ -432,7 +432,7 @@ static void convert(aiRecord *prec)
default: /* must use breakpoint table */
if (cvtRawToEngBpt(&val,prec->linr,prec->init,(void *)&prec->pbrk,&prec->lbrk)!=0) {
recGblSetSevr(prec,SOFT_ALARM,MAJOR_ALARM);
recGblSetSevrMsg(prec,SOFT_ALARM,MAJOR_ALARM, "BPT Error");
}
}
+3 -3
View File
@@ -236,7 +236,7 @@ static long process(struct dbCommon *pcommon)
}
if (fetch_values(prec) == 0) {
if (calcPerform(&prec->a, &prec->val, prec->rpcl)) {
recGblSetSevr(prec, CALC_ALARM, INVALID_ALARM);
recGblSetSevrMsg(prec, CALC_ALARM, INVALID_ALARM, "calcPerform");
} else {
prec->udf = isnan(prec->val);
}
@@ -610,7 +610,7 @@ static void execOutput(calcoutRecord *prec)
break;
case calcoutDOPT_Use_OVAL:
if (calcPerform(&prec->a, &prec->oval, prec->orpc)) {
recGblSetSevr(prec, CALC_ALARM, INVALID_ALARM);
recGblSetSevrMsg(prec, CALC_ALARM, INVALID_ALARM, "OCAL calcPerform");
} else {
prec->udf = isnan(prec->oval);
}
@@ -770,7 +770,7 @@ static long writeValue(calcoutRecord *prec)
if (!pcalcoutDSET || !pcalcoutDSET->write) {
errlogPrintf("%s DSET write does not exist\n", prec->name);
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
recGblSetSevrMsg(prec, SOFT_ALARM, INVALID_ALARM, "DSET write does not exist");
prec->pact = TRUE;
return(-1);
}
@@ -28,7 +28,5 @@ softIoc_LIBS = $(EPICS_BASE_IOC_LIBS)
DB += softIocExit.db
FINAL_LOCATION ?= $(shell $(PERL) $(TOOLS)/fullPathName.pl $(INSTALL_LOCATION))
CLEANS += epicsInstallDir.h
@@ -249,7 +249,10 @@ int main(int argc, char *argv[])
} else {
if (loadedDb || ranScript) {
epicsThreadExitMain();
// non-interactive IOC. spin forever
while(true) {
epicsThreadSleep(1000.0);
}
} else {
usage(argv[0], dbd_file);
-1
View File
@@ -40,7 +40,6 @@ HTMLS += dbdToHtml.html
# Build Package Config Files
FINAL_LOCATION ?= $(shell $(PERL) $(TOOLS)/fullPathName.pl $(INSTALL_LOCATION))
C_CFLAGS += $(filter-out -g,$(filter-out -O%,$(filter-out -W%,$(CPPFLAGS))))
C_CFLAGS += $(filter-out -g,$(filter-out -O%,$(filter-out -W%,$(CFLAGS))))
PKGVARS += FINAL_LOCATION OS_CLASS CMPLR_CLASS C_CFLAGS LDFLAGS LDLIBS