Merge 3.16 (after 3.16.2-rc1) into 7.0
This commit is contained in:
@@ -34,7 +34,7 @@
|
||||
#include "errlog.h"
|
||||
#include "errMdef.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsExport.h" /* #define epicsExportSharedSymbols */
|
||||
#include "caeventmask.h"
|
||||
#include "callback.h"
|
||||
#include "dbAccessDefs.h"
|
||||
@@ -65,6 +65,9 @@
|
||||
epicsShareDef struct dbBase *pdbbase = 0;
|
||||
epicsShareDef volatile int interruptAccept=FALSE;
|
||||
|
||||
epicsShareDef int dbAccessDebugPUTF = 0;
|
||||
epicsExportAddress(int, dbAccessDebugPUTF);
|
||||
|
||||
/* Hook Routines */
|
||||
|
||||
epicsShareDef DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL;
|
||||
@@ -446,22 +449,6 @@ int dbGetFieldIndex(const struct dbAddr *paddr)
|
||||
return paddr->pfldDes->indRecordType;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a record if its scan field is passive.
|
||||
* Will notify if processing is complete by callback.
|
||||
* (only if you are interested in completion)
|
||||
*/
|
||||
long dbScanPassive(dbCommon *pfrom, dbCommon *pto)
|
||||
{
|
||||
/* if not passive just return success */
|
||||
if (pto->scan != 0)
|
||||
return 0;
|
||||
|
||||
if (pfrom && pfrom->ppn)
|
||||
dbNotifyAdd(pfrom,pto);
|
||||
return dbProcess(pto);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the record.
|
||||
* 1. Check for breakpoints.
|
||||
@@ -527,7 +514,8 @@ long dbProcess(dbCommon *precord)
|
||||
unsigned short monitor_mask;
|
||||
|
||||
if (*ptrace)
|
||||
printf("%s: Active %s\n", context, precord->name);
|
||||
printf("%s: dbProcess of Active '%s' with RPRO=%d\n",
|
||||
context, precord->name, precord->rpro);
|
||||
|
||||
/* raise scan alarm after MAX_LOCK times */
|
||||
if ((precord->stat == SCAN_ALARM) ||
|
||||
@@ -556,7 +544,8 @@ long dbProcess(dbCommon *precord)
|
||||
/* if disabled check disable alarm severity and return success */
|
||||
if (precord->disa == precord->disv) {
|
||||
if (*ptrace)
|
||||
printf("%s: Disabled %s\n", context, precord->name);
|
||||
printf("%s: dbProcess of Disabled '%s'\n",
|
||||
context, precord->name);
|
||||
|
||||
/*take care of caching and notifyCompletion*/
|
||||
precord->rpro = FALSE;
|
||||
@@ -593,7 +582,7 @@ long dbProcess(dbCommon *precord)
|
||||
}
|
||||
|
||||
if (*ptrace)
|
||||
printf("%s: Process %s\n", context, precord->name);
|
||||
printf("%s: dbProcess of '%s'\n", context, precord->name);
|
||||
|
||||
/* process record */
|
||||
status = prset->process(precord);
|
||||
@@ -713,6 +702,18 @@ void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry)
|
||||
pdbentry->precnode = ppvt->recnode;
|
||||
}
|
||||
|
||||
struct link* dbGetDevLink(struct dbCommon* prec)
|
||||
{
|
||||
DBLINK *plink = 0;
|
||||
DBENTRY entry;
|
||||
dbInitEntryFromRecord(prec, &entry);
|
||||
if(dbFindField(&entry, "INP")==0 || dbFindField(&entry, "OUT")==0) {
|
||||
plink = (DBLINK*)entry.pfield;
|
||||
}
|
||||
dbFinishEntry(&entry);
|
||||
return plink;
|
||||
}
|
||||
|
||||
long dbValueSize(short dbr_type)
|
||||
{
|
||||
/* sizes for value associated with each DBR request type */
|
||||
@@ -1040,7 +1041,7 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
return S_db_badDbrtype;
|
||||
}
|
||||
|
||||
status = dbParseLink(pstring, pfldDes->field_type, &link_info, 0);
|
||||
status = dbParseLink(pstring, pfldDes->field_type, &link_info);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
@@ -1213,8 +1214,8 @@ long dbPutField(DBADDR *paddr, short dbrType,
|
||||
precord->scan == 0 &&
|
||||
dbrType < DBR_PUT_ACKT)) {
|
||||
if (precord->pact) {
|
||||
if (precord->tpro)
|
||||
printf("%s: Active %s\n",
|
||||
if (dbAccessDebugPUTF && precord->tpro)
|
||||
printf("%s: dbPutField to Active '%s', setting RPRO=1\n",
|
||||
epicsThreadGetNameSelf(), precord->name);
|
||||
precord->rpro = TRUE;
|
||||
} else {
|
||||
@@ -1347,4 +1348,3 @@ done:
|
||||
paddr->pfield = pfieldsave;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ extern "C" {
|
||||
|
||||
epicsShareExtern struct dbBase *pdbbase;
|
||||
epicsShareExtern volatile int interruptAccept;
|
||||
epicsShareExtern int dbAccessDebugPUTF;
|
||||
|
||||
/* The database field and request types are defined in dbFldTypes.h*/
|
||||
/* Data Base Request Options */
|
||||
|
||||
@@ -842,6 +842,7 @@ static void eventCallback(struct event_handler_args arg)
|
||||
struct dbr_time_double *pdbr_time_double;
|
||||
dbCaCallback monitor = 0;
|
||||
void *userPvt = 0;
|
||||
int doScan = 1;
|
||||
|
||||
assert(pca);
|
||||
epicsMutexMustLock(pca->lock);
|
||||
@@ -872,10 +873,13 @@ static void eventCallback(struct event_handler_args arg)
|
||||
memcpy(pca->pgetString, dbr_value_ptr(arg.dbr, arg.type), size);
|
||||
pca->gotInString = TRUE;
|
||||
} else switch (arg.type){
|
||||
case DBR_TIME_ENUM:
|
||||
/* Disable the record scan if we also have a string monitor */
|
||||
doScan = !(plink->value.pv_link.pvlMask & pvlOptInpString);
|
||||
/* fall through */
|
||||
case DBR_TIME_STRING:
|
||||
case DBR_TIME_SHORT:
|
||||
case DBR_TIME_FLOAT:
|
||||
case DBR_TIME_ENUM:
|
||||
case DBR_TIME_CHAR:
|
||||
case DBR_TIME_LONG:
|
||||
case DBR_TIME_DOUBLE:
|
||||
@@ -893,7 +897,7 @@ static void eventCallback(struct event_handler_args arg)
|
||||
pca->sevr = pdbr_time_double->severity;
|
||||
pca->stat = pdbr_time_double->status;
|
||||
memcpy(&pca->timeStamp, &pdbr_time_double->stamp, sizeof(epicsTimeStamp));
|
||||
if (precord) {
|
||||
if (doScan && precord) {
|
||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||
|
||||
if ((ppv_link->pvlMask & pvlOptCP) ||
|
||||
|
||||
@@ -12,6 +12,29 @@
|
||||
* Current Author: Andrew Johnson
|
||||
*/
|
||||
|
||||
/* The PUTF and RPRO fields in dbCommon are flags that indicate when a record
|
||||
* is being processed as a result of an external put (i.e. some server process
|
||||
* calling dbPutField()), ensuring that the record and its successors will
|
||||
* eventually get processed even if they happen to be busy at the time of the
|
||||
* put. From Base-3.16.2 and 7.0.2 the code ensures that all records downstream
|
||||
* from the original are processed even if a busy asynchronous device appears
|
||||
* in the processing chain (this breaks the chain in older versions).
|
||||
*
|
||||
* PUTF - This field is set in dbPutField() prior to it calling dbProcess().
|
||||
* It is normally cleared at the end of processing in recGblFwdLink().
|
||||
* It may also be cleared in dbProcess() if DISA==DISV (scan disabled),
|
||||
* or by the processTarget() function below.
|
||||
*
|
||||
* If PUTF is TRUE before a call to dbProcess(prec), then after it returns
|
||||
* either PACT is TRUE, or PUTF will be FALSE.
|
||||
*
|
||||
* RPRO - This field is set by dbPutField() or by the processTarget() function
|
||||
* below when a record to be processed is found to be busy (PACT==1).
|
||||
* It is normally cleared in recGblFwdLink() when the record is queued
|
||||
* for re-processing, or in dbProcess() if DISA==DISV (scan disabled).
|
||||
*/
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
@@ -43,17 +66,22 @@
|
||||
#include "dbNotify.h"
|
||||
#include "dbScan.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbServer.h"
|
||||
#include "devSup.h"
|
||||
#include "link.h"
|
||||
#include "recGbl.h"
|
||||
#include "recSup.h"
|
||||
#include "special.h"
|
||||
#include "dbDbLink.h"
|
||||
|
||||
|
||||
/***************************** Database Links *****************************/
|
||||
|
||||
/* Forward definition */
|
||||
/* Forward definitions */
|
||||
static lset dbDb_lset;
|
||||
|
||||
static long processTarget(dbCommon *psrc, dbCommon *pdst);
|
||||
|
||||
long dbDbInitLink(struct link *plink, short dbfType)
|
||||
{
|
||||
DBADDR dbaddr;
|
||||
@@ -138,11 +166,7 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
|
||||
/* scan passive records if link is process passive */
|
||||
if (ppv_link->pvlMask & pvlOptPP) {
|
||||
unsigned char pact = precord->pact;
|
||||
|
||||
precord->pact = TRUE;
|
||||
status = dbScanPassive(precord, paddr->precord);
|
||||
precord->pact = pact;
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
@@ -311,22 +335,10 @@ static long dbDbPutValue(struct link *plink, short dbrType,
|
||||
return status;
|
||||
|
||||
if (paddr->pfield == (void *) &pdest->proc ||
|
||||
(ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
|
||||
/* if dbPutField caused asyn record to process */
|
||||
/* ask for reprocessing*/
|
||||
if (pdest->putf) {
|
||||
pdest->rpro = TRUE;
|
||||
} else { /* process dest record with source's PACT true */
|
||||
unsigned char pact;
|
||||
|
||||
if (psrce && psrce->ppn)
|
||||
dbNotifyAdd(psrce, pdest);
|
||||
pact = psrce->pact;
|
||||
psrce->pact = TRUE;
|
||||
status = dbProcess(pdest);
|
||||
psrce->pact = pact;
|
||||
}
|
||||
(ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
|
||||
status = processTarget(psrce, pdest);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -356,3 +368,75 @@ static lset dbDb_lset = {
|
||||
dbDbPutValue, NULL,
|
||||
dbDbScanFwdLink, doLocked
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Process a record if its scan field is passive.
|
||||
*/
|
||||
long dbScanPassive(dbCommon *pfrom, dbCommon *pto)
|
||||
{
|
||||
/* if not passive we're done */
|
||||
if (pto->scan != 0)
|
||||
return 0;
|
||||
|
||||
return processTarget(pfrom, pto);
|
||||
}
|
||||
|
||||
static long processTarget(dbCommon *psrc, dbCommon *pdst)
|
||||
{
|
||||
char context[40] = "";
|
||||
int trace = dbAccessDebugPUTF && *dbLockSetAddrTrace(psrc);
|
||||
long status;
|
||||
epicsUInt8 pact = psrc->pact;
|
||||
|
||||
psrc->pact = TRUE;
|
||||
|
||||
if (psrc && psrc->ppn)
|
||||
dbNotifyAdd(psrc, pdst);
|
||||
|
||||
if (trace && dbServerClient(context, sizeof(context))) {
|
||||
/* No client, use thread name */
|
||||
strncpy(context, epicsThreadGetNameSelf(), sizeof(context));
|
||||
context[sizeof(context) - 1] = 0;
|
||||
}
|
||||
|
||||
if (!pdst->pact) {
|
||||
/* Normal propagation of PUTF from src to dst */
|
||||
if (trace)
|
||||
printf("%s: '%s' -> '%s' with PUTF=%u\n",
|
||||
context, psrc->name, pdst->name, psrc->putf);
|
||||
|
||||
if (pdst->putf)
|
||||
errlogPrintf("Warning: '%s.PUTF' found true with PACT false\n",
|
||||
pdst->name);
|
||||
|
||||
pdst->putf = psrc->putf;
|
||||
}
|
||||
else if (psrc->putf) {
|
||||
/* The dst record is busy (awaiting async reprocessing) and
|
||||
* we were originally triggered by a call to dbPutField(),
|
||||
* so we mark the dst record for reprocessing once the async
|
||||
* completion is over.
|
||||
*/
|
||||
if (trace)
|
||||
printf("%s: '%s' -> Active '%s', setting RPRO=1\n",
|
||||
context, psrc->name, pdst->name);
|
||||
|
||||
pdst->putf = FALSE;
|
||||
pdst->rpro = TRUE;
|
||||
}
|
||||
else {
|
||||
/* The dst record is busy, but we weren't triggered by a call
|
||||
* to dbPutField(). Do nothing.
|
||||
*/
|
||||
if (trace)
|
||||
printf("%s: '%s' -> Active '%s', done\n",
|
||||
context, psrc->name, pdst->name);
|
||||
}
|
||||
|
||||
status = dbProcess(pdst);
|
||||
|
||||
psrc->pact = pact;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* dbJLink.c */
|
||||
|
||||
@@ -25,19 +25,33 @@
|
||||
#include "dbLock.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "link.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define IFDEBUG(n) if(parser->parse_debug)
|
||||
epicsShareDef int dbJLinkDebug = 0;
|
||||
epicsExportAddress(int, dbJLinkDebug);
|
||||
|
||||
#define IFDEBUG(n) if (dbJLinkDebug >= (n))
|
||||
|
||||
typedef struct parseContext {
|
||||
jlink *pjlink;
|
||||
jlink *product;
|
||||
short dbfType;
|
||||
short jsonDepth;
|
||||
unsigned key_is_link:1;
|
||||
unsigned parse_debug:1;
|
||||
unsigned lset_debug:1;
|
||||
} parseContext;
|
||||
|
||||
epicsShareDef const char *jlif_result_name[2] = {
|
||||
"jlif_stop",
|
||||
"jlif_continue",
|
||||
};
|
||||
|
||||
epicsShareDef const char *jlif_key_result_name[5] = {
|
||||
"jlif_key_stop",
|
||||
"jlif_key_continue",
|
||||
"jlif_key_child_inlink",
|
||||
"jlif_key_child_outlink",
|
||||
"jlif_key_child_fwdlink"
|
||||
};
|
||||
|
||||
#define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine)
|
||||
|
||||
static int dbjl_return(parseContext *parser, jlif_result result) {
|
||||
@@ -45,8 +59,8 @@ static int dbjl_return(parseContext *parser, jlif_result result) {
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_return(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
|
||||
}
|
||||
|
||||
if (result == jlif_stop && pjlink) {
|
||||
@@ -59,6 +73,9 @@ static int dbjl_return(parseContext *parser, jlif_result result) {
|
||||
pjlink->pif->free_jlink(pjlink);
|
||||
}
|
||||
|
||||
IFDEBUG(10)
|
||||
printf(" returning %d %s\n", result,
|
||||
result == jlif_stop ? "*** STOP ***" : "Continue");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -68,8 +85,8 @@ static int dbjl_value(parseContext *parser, jlif_result result) {
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_value(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
|
||||
}
|
||||
|
||||
if (result == jlif_stop || pjlink->parseDepth > 0)
|
||||
@@ -81,7 +98,6 @@ static int dbjl_value(parseContext *parser, jlif_result result) {
|
||||
} else if (parent->pif->end_child) {
|
||||
parent->pif->end_child(parent, pjlink);
|
||||
}
|
||||
pjlink->debug = 0;
|
||||
|
||||
parser->pjlink = parent;
|
||||
|
||||
@@ -159,29 +175,46 @@ static int dbjl_start_map(void *ctx) {
|
||||
if (!pjlink) {
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_start_map(NULL)\t");
|
||||
printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->key_is_link);
|
||||
printf(" jsonDepth=%d, parseDepth=00, dbfType=%d\n",
|
||||
parser->jsonDepth, parser->dbfType);
|
||||
}
|
||||
|
||||
assert(parser->jsonDepth == 0);
|
||||
parser->jsonDepth++;
|
||||
parser->key_is_link = 1;
|
||||
return jlif_continue; /* Opening '{' */
|
||||
}
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_start_map(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
|
||||
}
|
||||
|
||||
pjlink->parseDepth++;
|
||||
parser->jsonDepth++;
|
||||
|
||||
result = CALL_OR_STOP(pjlink->pif->parse_start_map)(pjlink);
|
||||
if (result == jlif_key_child_link) {
|
||||
parser->key_is_link = 1;
|
||||
switch (result) {
|
||||
case jlif_key_child_inlink:
|
||||
parser->dbfType = DBF_INLINK;
|
||||
result = jlif_continue;
|
||||
break;
|
||||
case jlif_key_child_outlink:
|
||||
parser->dbfType = DBF_OUTLINK;
|
||||
result = jlif_continue;
|
||||
break;
|
||||
case jlif_key_child_fwdlink:
|
||||
parser->dbfType = DBF_FWDLINK;
|
||||
result = jlif_continue;
|
||||
break;
|
||||
case jlif_key_stop:
|
||||
case jlif_key_continue:
|
||||
break;
|
||||
default:
|
||||
errlogPrintf("dbJLinkInit: Bad return %d from '%s'::parse_start_map()\n",
|
||||
result, pjlink->pif->name);
|
||||
result = jlif_stop;
|
||||
break;
|
||||
}
|
||||
|
||||
IFDEBUG(10)
|
||||
@@ -196,8 +229,9 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
|
||||
char *link_name;
|
||||
linkSup *linkSup;
|
||||
jlif *pjlif;
|
||||
jlink *child;
|
||||
|
||||
if (!parser->key_is_link) {
|
||||
if (parser->dbfType == 0) {
|
||||
if (!pjlink) {
|
||||
errlogPrintf("dbJLinkInit: Illegal second link key '%.*s'\n",
|
||||
(int) len, key);
|
||||
@@ -207,8 +241,8 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_map_key(%s@%p, \"%.*s\")\t",
|
||||
pjlink->pif->name, pjlink, (int) len, key);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
|
||||
}
|
||||
|
||||
assert(pjlink->parseDepth > 0);
|
||||
@@ -219,8 +253,8 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_map_key(NULL, \"%.*s\")\t", (int) len, key);
|
||||
printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->key_is_link);
|
||||
printf(" jsonDepth=%d, parseDepth=00, dbfType=%d\n",
|
||||
parser->jsonDepth, parser->dbfType);
|
||||
}
|
||||
|
||||
link_name = dbmfStrndup((const char *) key, len);
|
||||
@@ -241,27 +275,35 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
|
||||
return dbjl_return(parser, jlif_stop);
|
||||
}
|
||||
|
||||
dbmfFree(link_name);
|
||||
|
||||
pjlink = pjlif->alloc_jlink(parser->dbfType);
|
||||
if (!pjlink) {
|
||||
errlogPrintf("dbJLinkInit: Out of memory\n");
|
||||
child = pjlif->alloc_jlink(parser->dbfType);
|
||||
if (!child) {
|
||||
errlogPrintf("dbJLinkInit: Link type '%s' allocation failed. \n",
|
||||
link_name);
|
||||
dbmfFree(link_name);
|
||||
return dbjl_return(parser, jlif_stop);
|
||||
}
|
||||
pjlink->pif = pjlif;
|
||||
pjlink->parent = NULL;
|
||||
pjlink->parseDepth = 0;
|
||||
pjlink->debug = !!parser->lset_debug;
|
||||
|
||||
child->pif = pjlif;
|
||||
child->parseDepth = 0;
|
||||
child->debug = 0;
|
||||
|
||||
if (parser->pjlink) {
|
||||
/* We're starting a child link, save its parent */
|
||||
pjlink->parent = parser->pjlink;
|
||||
child->parent = pjlink;
|
||||
|
||||
if (pjlink->pif->start_child)
|
||||
pjlink->pif->start_child(pjlink, child);
|
||||
}
|
||||
parser->pjlink = pjlink;
|
||||
parser->key_is_link = 0;
|
||||
else
|
||||
child->parent = NULL;
|
||||
|
||||
parser->pjlink = child;
|
||||
parser->dbfType = 0;
|
||||
|
||||
dbmfFree(link_name);
|
||||
|
||||
IFDEBUG(8)
|
||||
printf("dbjl_map_key: New %s@%p\n", pjlink ? pjlink->pif->name : "", pjlink);
|
||||
printf("dbjl_map_key: New %s@%p\n", child ? child->pif->name : "", child);
|
||||
|
||||
return jlif_continue;
|
||||
}
|
||||
@@ -274,9 +316,9 @@ static int dbjl_end_map(void *ctx) {
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_end_map(%s@%p)\t",
|
||||
pjlink ? pjlink->pif->name : "NULL", pjlink);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0,
|
||||
parser->key_is_link);
|
||||
parser->dbfType);
|
||||
}
|
||||
|
||||
parser->jsonDepth--;
|
||||
@@ -298,8 +340,8 @@ static int dbjl_start_array(void *ctx) {
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_start_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
|
||||
}
|
||||
|
||||
assert(pjlink);
|
||||
@@ -316,8 +358,8 @@ static int dbjl_end_array(void *ctx) {
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_end_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
|
||||
}
|
||||
|
||||
assert(pjlink);
|
||||
@@ -335,7 +377,7 @@ static yajl_callbacks dbjl_callbacks = {
|
||||
};
|
||||
|
||||
long dbJLinkParse(const char *json, size_t jlen, short dbfType,
|
||||
jlink **ppjlink, unsigned opts)
|
||||
jlink **ppjlink)
|
||||
{
|
||||
parseContext context, *parser = &context;
|
||||
yajl_alloc_funcs dbjl_allocs;
|
||||
@@ -347,17 +389,14 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
|
||||
parser->product = NULL;
|
||||
parser->dbfType = dbfType;
|
||||
parser->jsonDepth = 0;
|
||||
parser->key_is_link = 0;
|
||||
parser->parse_debug = !!(opts&LINK_DEBUG_JPARSE);
|
||||
parser->lset_debug = !!(opts&LINK_DEBUG_LSET);
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbJLinkInit(\"%.*s\", %d, %p)\n",
|
||||
(int) jlen, json, dbfType, ppjlink);
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbJLinkInit: jsonDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->key_is_link);
|
||||
printf("dbJLinkInit: jsonDepth=%d, dbfType=%d\n",
|
||||
parser->jsonDepth, parser->dbfType);
|
||||
|
||||
yajl_set_default_alloc_funcs(&dbjl_allocs);
|
||||
yh = yajl_alloc(&dbjl_callbacks, &dbjl_allocs, parser);
|
||||
@@ -365,8 +404,14 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
|
||||
return S_db_noMemory;
|
||||
|
||||
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
|
||||
if (ys == yajl_status_ok)
|
||||
IFDEBUG(10)
|
||||
printf("dbJLinkInit: yajl_parse() returned %d\n", ys);
|
||||
|
||||
if (ys == yajl_status_ok) {
|
||||
ys = yajl_complete_parse(yh);
|
||||
IFDEBUG(10)
|
||||
printf("dbJLinkInit: yajl_complete_parse() returned %d\n", ys);
|
||||
}
|
||||
|
||||
switch (ys) {
|
||||
unsigned char *err;
|
||||
@@ -378,6 +423,9 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
|
||||
break;
|
||||
|
||||
case yajl_status_error:
|
||||
IFDEBUG(10)
|
||||
printf(" jsonDepth=%d, product=%p, pjlink=%p\n",
|
||||
parser->jsonDepth, parser->product, parser->pjlink);
|
||||
err = yajl_get_error(yh, 1, (const unsigned char *) json, jlen);
|
||||
errlogPrintf("dbJLinkInit: %s\n", err);
|
||||
yajl_free_error(yh, err);
|
||||
@@ -389,18 +437,24 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
|
||||
}
|
||||
|
||||
yajl_free(yh);
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbJLinkInit: returning status=0x%lx\n\n",
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
long dbJLinkInit(struct link *plink)
|
||||
{
|
||||
jlink *pjlink;
|
||||
|
||||
assert(plink);
|
||||
pjlink = plink->value.json.jlink;
|
||||
|
||||
if (pjlink)
|
||||
plink->lset = pjlink->pif->get_lset(pjlink);
|
||||
if (plink->type == JSON_LINK) {
|
||||
jlink *pjlink = plink->value.json.jlink;
|
||||
|
||||
if (pjlink)
|
||||
plink->lset = pjlink->pif->get_lset(pjlink);
|
||||
}
|
||||
|
||||
dbLinkOpen(plink);
|
||||
return 0;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* dbJLink.h */
|
||||
|
||||
@@ -21,12 +21,16 @@ typedef enum {
|
||||
jlif_continue = 1
|
||||
} jlif_result;
|
||||
|
||||
epicsShareExtern const char *jlif_result_name[2];
|
||||
|
||||
typedef enum {
|
||||
jlif_key_stop = jlif_stop,
|
||||
jlif_key_continue = jlif_continue,
|
||||
jlif_key_child_link
|
||||
jlif_key_child_inlink, jlif_key_child_outlink, jlif_key_child_fwdlink
|
||||
} jlif_key_result;
|
||||
|
||||
epicsShareExtern const char *jlif_key_result_name[5];
|
||||
|
||||
struct link;
|
||||
struct lset;
|
||||
struct jlif;
|
||||
@@ -35,7 +39,7 @@ typedef struct jlink {
|
||||
struct jlif *pif; /* Link methods */
|
||||
struct jlink *parent; /* NULL for top-level links */
|
||||
int parseDepth; /* Used by parser, unused afterwards */
|
||||
unsigned debug:1; /* set by caller of jlif operations to request debug output to console */
|
||||
unsigned debug:1; /* Set to request debug output to console */
|
||||
/* Link types extend or embed this structure for private storage */
|
||||
} jlink;
|
||||
|
||||
@@ -72,8 +76,9 @@ typedef struct jlif {
|
||||
/* Optional, parser saw a string value */
|
||||
|
||||
jlif_key_result (*parse_start_map)(jlink *);
|
||||
/* Optional, parser saw an open-brace '{'. Return jlif_key_child_link
|
||||
* to expect a child link next (extra key/value pairs may follow).
|
||||
/* Optional, parser saw an open-brace '{'. Return jlif_key_child_inlink,
|
||||
* jlif_key_child_outlink, or jlif_key_child_fwdlink to expect a child
|
||||
* link next (extra key/value pairs may follow)
|
||||
*/
|
||||
|
||||
jlif_result (*parse_map_key)(jlink *, const char *key, size_t len);
|
||||
@@ -90,7 +95,8 @@ typedef struct jlif {
|
||||
|
||||
void (*end_child)(jlink *parent, jlink *child);
|
||||
/* Optional, called with pointer to the new child link after
|
||||
* parse_start_map() returned jlif_key_child_link */
|
||||
* the child link has finished parsing successfully
|
||||
*/
|
||||
|
||||
struct lset* (*get_lset)(const jlink *);
|
||||
/* Required, return lset for this link instance */
|
||||
@@ -98,7 +104,7 @@ typedef struct jlif {
|
||||
void (*report)(const jlink *, int level, int indent);
|
||||
/* Optional, print status information about this link instance, then
|
||||
* if (level > 0) print a link identifier (at indent+2) and call
|
||||
* dbJLinkReport(child, level-1, indent+4)
|
||||
* dbJLinkReport(child, level-1, indent+4)
|
||||
* for each child.
|
||||
*/
|
||||
|
||||
@@ -107,13 +113,19 @@ typedef struct jlif {
|
||||
* Stop immediately and return status if non-zero.
|
||||
*/
|
||||
|
||||
void (*start_child)(jlink *parent, jlink *child);
|
||||
/* Optional, called with pointer to the new child link after
|
||||
* parse_start_map() returned a jlif_key_child_link value and
|
||||
* the child link has been allocated (but not parsed yet)
|
||||
*/
|
||||
|
||||
/* Link types must NOT extend this table with their own routines,
|
||||
* this space is reserved for extensions to the jlink interface.
|
||||
*/
|
||||
} jlif;
|
||||
|
||||
epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType,
|
||||
jlink **ppjlink, unsigned opts);
|
||||
jlink **ppjlink);
|
||||
epicsShareFunc long dbJLinkInit(struct link *plink);
|
||||
|
||||
epicsShareFunc void dbJLinkFree(jlink *);
|
||||
@@ -130,4 +142,3 @@ epicsShareFunc long dbJLinkMapAll(char *recname, jlink_map_fn rtn, void *ctx);
|
||||
#endif
|
||||
|
||||
#endif /* INC_dbJLink_H */
|
||||
|
||||
|
||||
@@ -265,8 +265,19 @@ int dbIsLinkConnected(const struct link *plink)
|
||||
{
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (!plset || !plset->isConnected)
|
||||
if (!plset)
|
||||
return FALSE;
|
||||
if (!plset->isVolatile)
|
||||
return TRUE;
|
||||
|
||||
if (!plset->isConnected) {
|
||||
struct dbCommon *precord = plink->precord;
|
||||
|
||||
errlogPrintf("dbLink: Link type for '%s.%s' is volatile but has no"
|
||||
" lset::isConnected() method\n",
|
||||
precord->name, dbLinkFieldName(plink));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return plset->isConnected(plink);
|
||||
}
|
||||
|
||||
@@ -27,54 +27,337 @@ extern "C" {
|
||||
|
||||
struct dbLocker;
|
||||
|
||||
/** @file dbLink.h
|
||||
* @brief Link Support API
|
||||
*
|
||||
* Link support run-time API, all link types provide an lset which is used by
|
||||
* the IOC database to control and operate the link. This file also declares the
|
||||
* dbLink routines that IOC, record and device code can call to perform link
|
||||
* operations.
|
||||
*/
|
||||
|
||||
/** @brief callback routine for locked link operations
|
||||
*
|
||||
* Called by the lset::doLocked method to permit multiple link operations
|
||||
* while the link instance is locked.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param priv context for the callback routine
|
||||
*/
|
||||
typedef long (*dbLinkUserCallback)(struct link *plink, void *priv);
|
||||
|
||||
/** @brief Link Support Entry Table
|
||||
*
|
||||
* This structure provides information about and methods for an individual link
|
||||
* type. A pointer to this structure is included in every link's lset field, and
|
||||
* is used to perform operations on the link. For JSON links the pointer is
|
||||
* obtained by calling pjlink->pif->get_lset() at link initialization time,
|
||||
* immediately before calling dbLinkOpen() to activate the link.
|
||||
*/
|
||||
typedef struct lset {
|
||||
/* Characteristics of the link type */
|
||||
|
||||
/** @brief link constancy
|
||||
*
|
||||
* 1 means this is a constant link type whose value doesn't change.
|
||||
* The link's value will be obtained using one of the methods loadScalar,
|
||||
* loadLS or loadArray.
|
||||
*/
|
||||
const unsigned isConstant:1;
|
||||
|
||||
/** @brief link volatility
|
||||
*
|
||||
* 0 means the link is always connected.
|
||||
*/
|
||||
const unsigned isVolatile:1;
|
||||
|
||||
/* Activation */
|
||||
/** @brief activate link
|
||||
*
|
||||
* Optional, called whenever a JSON link is initialized or added at runtime.
|
||||
*
|
||||
* @param plink the link
|
||||
*/
|
||||
void (*openLink)(struct link *plink);
|
||||
|
||||
/* Destructor */
|
||||
/** @brief deactivate link
|
||||
*
|
||||
* Optional, called whenever a link address is changed at runtime, or the
|
||||
* IOC is shutting down.
|
||||
*
|
||||
* @param locker
|
||||
* @param plink the link
|
||||
*/
|
||||
void (*removeLink)(struct dbLocker *locker, struct link *plink);
|
||||
|
||||
/* Const init, data type hinting */
|
||||
/* Constant link initialization and data type hinting */
|
||||
|
||||
/** @brief load constant scalar from link type
|
||||
*
|
||||
* Usually called during IOC initialization, constant link types must copy a
|
||||
* scalar value of the indicated data type to the buffer provided and return
|
||||
* 0. A non-constant link type can use this method call as an early hint
|
||||
* that subsequent calls to dbGetLink() will request scalar data of the
|
||||
* indicated type, although the type might change.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param dbrType data type code
|
||||
* @param pbuffer where to put the value
|
||||
* @returns 0 if a value was loaded, non-zero otherwise
|
||||
*/
|
||||
long (*loadScalar)(struct link *plink, short dbrType, void *pbuffer);
|
||||
|
||||
/** @brief load constant long string from link type
|
||||
*
|
||||
* Usually called during IOC initialization, constant link types must copy a
|
||||
* nil-terminated string up to size characters long to the buffer provided,
|
||||
* and write the length of that string to the plen location. A non-constant
|
||||
* link type can use this as an early hint that subsequent calls to
|
||||
* dbGetLink() will request long string data, although this might change.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param pbuffer where to put the string
|
||||
* @param size length of pbuffer in chars
|
||||
* @param plen set to number of chars written
|
||||
* @returns status value
|
||||
*/
|
||||
long (*loadLS)(struct link *plink, char *pbuffer, epicsUInt32 size,
|
||||
epicsUInt32 *plen);
|
||||
|
||||
/** @brief load constant array from link type
|
||||
*
|
||||
* Usually called during IOC initialization, constant link types must copy
|
||||
* an array value of the indicated data type to the buffer provided, update
|
||||
* the pnRequest location to indicate how many elements were loaded, and
|
||||
* return 0. A non-constant link type can use this method call as an early
|
||||
* hint that subsequent calls to dbGetLink() will request array data of the
|
||||
* indicated type and max size, although the request might change.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param dbrType data type code
|
||||
* @param pbuffer where to put the value
|
||||
* @param pnRequest Max elements on entry, actual on exit
|
||||
* @returns 0 if elements were loaded, non-zero otherwise
|
||||
*/
|
||||
long (*loadArray)(struct link *plink, short dbrType, void *pbuffer,
|
||||
long *pnRequest);
|
||||
|
||||
/* Metadata */
|
||||
|
||||
/** @brief return link connection status
|
||||
*
|
||||
* Return an indication whether this link is connected or not. This routine
|
||||
* is polled by the calcout and some external record types. Not required for
|
||||
* non-volatile link types, which are by definition always connected.
|
||||
*
|
||||
* @param plink the link
|
||||
* @returns 1 if connected, 0 if disconnected
|
||||
*/
|
||||
int (*isConnected)(const struct link *plink);
|
||||
|
||||
/** @brief get data type of link destination
|
||||
*
|
||||
* Called on both input and output links by long string support code to
|
||||
* decide whether to use DBR_CHAR/DBR_UCHAR or DBR_STRING for a subsequent
|
||||
* dbPutLink() or dbGetLink() call. Optional, but if not provided long
|
||||
* strings cannot be transported over this link type, and no warning or
|
||||
* error will appear to explain why. Not required for constant link types.
|
||||
*
|
||||
* @param plink the link
|
||||
* @returns DBF_* type code, or -1 on error/disconnected link
|
||||
*/
|
||||
int (*getDBFtype)(const struct link *plink);
|
||||
long (*getElements)(const struct link *plink, long *nelements);
|
||||
|
||||
/* Get data */
|
||||
|
||||
/** @brief get array size of an input link
|
||||
*
|
||||
* Called on input links by the compress record type for memory allocation
|
||||
* purposes, before using the dbGetLink() routine to fetch the actual
|
||||
* array data.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param pnElements where to put the answer
|
||||
* @returns status value
|
||||
*/
|
||||
long (*getElements)(const struct link *plink, long *pnElements);
|
||||
|
||||
/** @brief get value from an input link
|
||||
*
|
||||
* Called to fetch data from the link, which must be converted into the
|
||||
* given data type and placed in the buffer indicated. The actual number of
|
||||
* elements retrieved should be updated in the pnRequest location. If this
|
||||
* method returns an error status value, the link's record will be placed
|
||||
* into an Invalid severity / Link Alarm state by the dbGetLink() routine
|
||||
* that calls this method.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param dbrType data type code
|
||||
* @param pbuffer where to put the value
|
||||
* @param pnRequest max elements on entry, actual on exit
|
||||
* @returns status value
|
||||
*/
|
||||
long (*getValue)(struct link *plink, short dbrType, void *pbuffer,
|
||||
long *pnRequest);
|
||||
|
||||
/** @brief get the control range for an output link
|
||||
*
|
||||
* Called to fetch the control range for the link target, as a pair of
|
||||
* double values for the lowest and highest values that the target will
|
||||
* accept. This method is not used at all by the IOC or built-in record
|
||||
* types, although external record types may require it.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param lo lowest accepted value
|
||||
* @param hi highest accepted value
|
||||
* @returns status value
|
||||
*/
|
||||
long (*getControlLimits)(const struct link *plink, double *lo, double *hi);
|
||||
|
||||
/** @brief get the display range from an input link
|
||||
*
|
||||
* Called to fetch the display range for an input link target, as a pair of
|
||||
* double values for the lowest and highest values that the PV expects to
|
||||
* return. This method is used by several built-in record types to obtain
|
||||
* the display range for their generic input links.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param lo lowest accepted value
|
||||
* @param hi highest accepted value
|
||||
* @returns status value
|
||||
*/
|
||||
long (*getGraphicLimits)(const struct link *plink, double *lo, double *hi);
|
||||
|
||||
/** @brief get the alarm limits from an input link
|
||||
*
|
||||
* Called to fetch the alarm limits for an input link target, as four
|
||||
* double values for the warning and alarm levels that the PV checks its
|
||||
* value against. This method is used by several built-in record types to
|
||||
* obtain the alarm limits for their generic input links.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param lolo low alarm value
|
||||
* @param lo low warning value
|
||||
* @param hi high warning value
|
||||
* @param hihi high alarm value
|
||||
* @returns status value
|
||||
*/
|
||||
long (*getAlarmLimits)(const struct link *plink, double *lolo, double *lo,
|
||||
double *hi, double *hihi);
|
||||
|
||||
/** @brief get the precision from an input link
|
||||
*
|
||||
* Called to fetch the precision for an input link target. This method is
|
||||
* used by several built-in record types to obtain the precision for their
|
||||
* generic input links.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param precision where to put the answer
|
||||
* @returns status value
|
||||
*/
|
||||
long (*getPrecision)(const struct link *plink, short *precision);
|
||||
|
||||
/** @brief get the units string from an input link
|
||||
*
|
||||
* Called to fetch the units string for an input link target. This method is
|
||||
* used by several built-in record types to obtain the units string for
|
||||
* their generic input links.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param units where to put the answer
|
||||
* @param unitsSize buffer size for the answer
|
||||
* @returns status value
|
||||
*/
|
||||
long (*getUnits)(const struct link *plink, char *units, int unitsSize);
|
||||
|
||||
/** @brief get the alarm condition from an input link
|
||||
*
|
||||
* Called to fetch the alarm status and severity for an input link target.
|
||||
* Either status or severity pointers may be NULL when that value is not
|
||||
* needed by the calling code. This method is used by several built-in
|
||||
* record types to obtain the alarm condition for their generic input links.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param status where to put the alarm status (or NULL)
|
||||
* @param severity where to put the severity (or NULL)
|
||||
* @returns status value
|
||||
*/
|
||||
long (*getAlarm)(const struct link *plink, epicsEnum16 *status,
|
||||
epicsEnum16 *severity);
|
||||
|
||||
/** @brief get the time-stamp from an input link
|
||||
*
|
||||
* Called to fetch the time-stamp for an input link target. This method is
|
||||
* used by many built-in device supports to obtain the precision for their
|
||||
* generic input links.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param pstamp where to put the answer
|
||||
* @returns status value
|
||||
*/
|
||||
long (*getTimeStamp)(const struct link *plink, epicsTimeStamp *pstamp);
|
||||
|
||||
/* Put data */
|
||||
|
||||
/** @brief put a value to an output link
|
||||
*
|
||||
* Called to send nRequest elements of type dbrType found at pbuffer to an
|
||||
* output link target.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param dbrType data type code
|
||||
* @param pbuffer where to put the value
|
||||
* @param nRequest number of elements to send
|
||||
* @returns status value
|
||||
*/
|
||||
long (*putValue)(struct link *plink, short dbrType,
|
||||
const void *pbuffer, long nRequest);
|
||||
|
||||
/** @brief put a value to an output link with asynchronous completion
|
||||
*
|
||||
* Called to send nRequest elements of type dbrType found at pbuffer to an
|
||||
* output link target. If the return status is zero, the link type will
|
||||
* later indicate the put has completed by calling dbLinkAsyncComplete()
|
||||
* from a background thread, which will be used to continue the record
|
||||
* process operation from where it left off.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param dbrType data type code
|
||||
* @param pbuffer where to put the value
|
||||
* @param nRequest number of elements to send
|
||||
* @returns status value
|
||||
*/
|
||||
long (*putAsync)(struct link *plink, short dbrType,
|
||||
const void *pbuffer, long nRequest);
|
||||
|
||||
/* Process */
|
||||
|
||||
/** @brief trigger processing of a forward link
|
||||
*
|
||||
* Called to trigger processing of the record pointed to by a forward link.
|
||||
* This routine is optional, but if not provided no warning message will be
|
||||
* shown when called by dbScanFwdLink(). JSON link types that do not support
|
||||
* this operation should return NULL from their jlif::alloc_jlink() method
|
||||
* if it gets called with a dbfType of DBF_FWDLINK.
|
||||
*
|
||||
* @param plink the link
|
||||
*/
|
||||
void (*scanForward)(struct link *plink);
|
||||
|
||||
/* Atomicity */
|
||||
|
||||
/** @brief execute a callback routine with link locked
|
||||
*
|
||||
* Called on an input link when multiple link attributes need to be fetched
|
||||
* in an atomic fashion. The link type must call the callback routine and
|
||||
* prevent any background I/O from updating any cached link data until that
|
||||
* routine returns. This method is used by most input device support to
|
||||
* fetch the timestamp along with the value when the record's TSE field is
|
||||
* set to epicsTimeEventDeviceTime.
|
||||
*
|
||||
* @param plink the link
|
||||
* @param rtn routine to execute
|
||||
* @returns status value
|
||||
*/
|
||||
long (*doLocked)(struct link *plink, dbLinkUserCallback rtn, void *priv);
|
||||
} lset;
|
||||
|
||||
@@ -99,7 +382,7 @@ epicsShareFunc long dbLoadLink(struct link *plink, short dbrType,
|
||||
epicsShareFunc long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer,
|
||||
long *pnRequest);
|
||||
|
||||
epicsShareFunc long dbGetNelements(const struct link *plink, long *nelements);
|
||||
epicsShareFunc long dbGetNelements(const struct link *plink, long *pnElements);
|
||||
epicsShareFunc int dbIsLinkConnected(const struct link *plink); /* 0 or 1 */
|
||||
epicsShareFunc int dbGetLinkDBFtype(const struct link *plink);
|
||||
epicsShareFunc long dbTryGetLink(struct link *, short dbrType, void *pbuffer,
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#ifndef INCdbLockh
|
||||
#define INCdbLockh
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "ellLib.h"
|
||||
#include "shareLib.h"
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "menuScan.h"
|
||||
#include "shareLib.h"
|
||||
#include "compilerDependencies.h"
|
||||
#include "devSup.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -33,9 +34,7 @@ extern "C" {
|
||||
#define MIN_PHASE SHRT_MIN
|
||||
|
||||
/*definitions for I/O Interrupt Scanning */
|
||||
struct ioscan_head;
|
||||
|
||||
typedef struct ioscan_head *IOSCANPVT;
|
||||
/* IOSCANPVT now defined in devSup.h */
|
||||
typedef struct event_list *EVENTPVT;
|
||||
|
||||
struct dbCommon;
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @file dbState.h
|
||||
* @brief Generic IOC state facility
|
||||
*
|
||||
@@ -89,4 +93,9 @@ epicsShareFunc void dbStateShow(dbStateId id, unsigned int level);
|
||||
*/
|
||||
epicsShareFunc void dbStateShowAll(unsigned int level);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // INCdbStateH
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "alarm.h"
|
||||
#include "dbDefs.h"
|
||||
#include "alarm.h"
|
||||
#include "epicsMath.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "epicsStdlib.h"
|
||||
@@ -180,6 +181,9 @@ unsigned short recGblResetAlarms(void *precord)
|
||||
epicsEnum16 val_mask = 0;
|
||||
epicsEnum16 stat_mask = 0;
|
||||
|
||||
if (new_sevr > INVALID_ALARM)
|
||||
new_sevr = INVALID_ALARM;
|
||||
|
||||
pdbc->stat = new_stat;
|
||||
pdbc->sevr = new_sevr;
|
||||
pdbc->nsta = 0;
|
||||
|
||||
Reference in New Issue
Block a user