Merge 3.16 (after 3.16.2-rc1) into 7.0

This commit is contained in:
Andrew Johnson
2018-10-26 17:04:53 -05:00
157 changed files with 5520 additions and 1623 deletions

View File

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

View File

@@ -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 */

View File

@@ -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) ||

View File

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

View File

@@ -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;

View File

@@ -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 */

View File

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

View File

@@ -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,

View File

@@ -13,6 +13,8 @@
#ifndef INCdbLockh
#define INCdbLockh
#include <stddef.h>
#include "ellLib.h"
#include "shareLib.h"

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -2241,7 +2241,7 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
if(!plink->text)
continue;
if(dbParseLink(plink->text, pflddes->field_type, &link_info, 0)!=0) {
if(dbParseLink(plink->text, pflddes->field_type, &link_info)!=0) {
/* This was already parsed once when ->text was set.
* Any syntax error messages were printed at that time.
*/
@@ -2270,7 +2270,7 @@ void dbFreeLinkInfo(dbLinkInfo *pinfo)
pinfo->target = NULL;
}
long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts)
long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
{
char *pstr;
size_t len;
@@ -2306,7 +2306,7 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts)
/* Check for braces => JSON */
if (*str == '{' && str[len-1] == '}') {
if (dbJLinkParse(str, len, ftype, &pinfo->jlink, opts))
if (dbJLinkParse(str, len, ftype, &pinfo->jlink))
goto fail;
pinfo->ltype = JSON_LINK;
@@ -2353,9 +2353,13 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts)
else if (strcmp(pinfo->hwid, "VS")==0) pinfo->ltype = VXI_IO;
else goto fail;
if (parm && pinfo->ltype != RF_IO) {
/* move parm string to beginning of buffer */
memmove(pinfo->target, parm, len + 1);
if (pinfo->ltype != RF_IO) {
if (!parm) {
pinfo->target[0] = '\0';
} else {
/* move parm string to beginning of buffer */
memmove(pinfo->target, parm, len + 1);
}
} else if (!parm && pinfo->ltype == RF_IO) {
/* RF_IO, the string isn't needed at all */
free(pinfo->target);
@@ -2641,21 +2645,8 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
case DBF_FWDLINK: {
dbLinkInfo link_info;
DBLINK *plink = (DBLINK *)pfield;
DBENTRY infoentry;
unsigned opts = 0;
if(pdbentry->precnode && ellCount(&pdbentry->precnode->infoList)) {
dbCopyEntryContents(pdbentry, &infoentry);
if(dbFindInfo(&infoentry, "base:lsetDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0)
opts |= LINK_DEBUG_LSET;
if(dbFindInfo(&infoentry, "base:jlinkDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0)
opts |= LINK_DEBUG_JPARSE;
dbFinishEntry(&infoentry);
}
status = dbParseLink(pstring, pflddes->field_type, &link_info, opts);
status = dbParseLink(pstring, pflddes->field_type, &link_info);
if (status) break;
if (plink->type==CONSTANT && plink->value.constantStr==NULL) {

View File

@@ -5,7 +5,7 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are 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.
\*************************************************************************/
/* dbStaticPvt.h */
/*
@@ -59,13 +59,10 @@ typedef struct dbLinkInfo {
long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec);
#define LINK_DEBUG_LSET 1
#define LINK_DEBUG_JPARSE 2
/* Parse link string. no record locks needed.
* on success caller must free pinfo->target
*/
epicsShareFunc long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts);
epicsShareFunc long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo);
/* Check if link type allow the parsed link value pinfo
* to be assigned to the given link.
* Record containing plink must be locked.

View File

@@ -6,7 +6,11 @@
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* devSup.h Device Support */
/** @file devSup.h
*
* @brief Device support routines
*/
/*
* Author: Marty Kraimer
* Date: 6-1-90
@@ -21,6 +25,111 @@
/* structures defined elsewhere */
struct dbCommon;
struct devSup;
typedef struct ioscan_head *IOSCANPVT;
struct link; /* aka DBLINK */
/** Type safe version of 'struct dset'
*
* Recommended usage:
*
* In Makefile:
@code
USR_CFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET
@endcode
*
* In C source file:
@code
#include <devSup.h>
#include <dbScan.h> // For IOCSCANPVT
...
#include <epicsExport.h> // defines epicsExportSharedSymbols
...
static long init_record(dbCommon *prec);
static long get_iointr_info(int detach, dbCommon *prec, IOCSCANPVT* pscan);
static long longin_read(longinRecord *prec);
const struct {
dset common;
long (*read)(longinRecord *prec);
} devLiDevName = {
{
5, // 4 from dset + 1 from longinRecord
NULL,
NULL,
&init_record,
&get_iointr_info
},
&longin_read
};
epicsExportAddress(dset, devLiDevName);
@endcode
*/
typedef struct typed_dset {
/** Number of function pointers which follow.
* The value depends on the recordtype, but must be >=4 */
long number;
/** Called from dbior() */
long (*report)(int lvl);
/** Called twice during iocInit().
* First with @a after = 0 before init_record() or array field allocation.
* Again with @a after = 1 after init_record() has finished.
*/
long (*init)(int after);
/** Called once per record instance */
long (*init_record)(struct dbCommon *prec);
/** Called when SCAN="I/O Intr" on startup, or after SCAN is changed.
*
* Caller must assign the third arguement (IOCSCANPVT*). eg.
@code
struct mpvt {
IOSCANPVT drvlist;
};
...
// init_record() routine calls
scanIoInit(&pvt->drvlist);
...
static long get_ioint_info(int detach, struct dbCommon *prec, IOCSCANPVT* pscan) {
if(prec->dpvt)
*pscan = &((mypvt*)prec->dpvt)->drvlist;
@endcode
*
* When a particular record instance can/will only used a single scan list,
* the @a detach argument can be ignored.
*
* If this is not the case, then the following should be noted.
* + get_ioint_info() is called with @a detach = 0 to fetch the scan list to
* which this record will be added.
* + get_ioint_info() is called later with @a detach = 1 to fetch the scan
* list from which this record should be removed.
* + Calls will be balanced, so a call with @a detach = 0 will be followed
* by one with @a detach = 1.
*
* @note get_ioint_info() will be called during IOC shutdown if the
* dsxt::del_record() extended callback is defined. (from 3.15.0.1)
*/
long (*get_ioint_info)(int detach, struct dbCommon *prec, IOSCANPVT* pscan);
/* Any further functions are specified by the record type. */
} typed_dset;
/** Device support extension table.
*
* Optional routines to allow run-time address modifications to be communicated
* to device support, which must register a struct dsxt by calling devExtend()
* from its init() routine.
*/
typedef struct dsxt {
/** Optional, called to offer device support a new record to control.
*
* Routine may return a non-zero error code to refuse record.
*/
long (*add_record)(struct dbCommon *precord);
/** Optional, called to remove record from device support control.
*
* Routine return a non-zero error code to refuse record removal.
*/
long (*del_record)(struct dbCommon *precord);
/* Only future Base releases may extend this table. */
} dsxt;
#ifdef __cplusplus
extern "C" {
@@ -29,6 +138,8 @@ extern "C" {
typedef long (*DEVSUPFUN)(); /* ptr to device support function*/
#endif
#ifndef USE_TYPED_DSET
typedef struct dset { /* device support entry table */
long number; /*number of support routines*/
DEVSUPFUN report; /*print report*/
@@ -38,11 +149,15 @@ typedef struct dset { /* device support entry table */
/*other functions are record dependent*/
} dset;
typedef struct dsxt { /* device support extension table */
long (*add_record)(struct dbCommon *precord);
long (*del_record)(struct dbCommon *precord);
/* Recordtypes are *not* allowed to extend this table */
} dsxt;
#else
typedef typed_dset dset;
#endif /* USE_TYPED_DSET */
/** Fetch INP or OUT link (or NULL if record type has neither).
*
* Recommended for use in device support init_record()
*/
epicsShareFunc struct link* dbGetDevLink(struct dbCommon* prec);
epicsShareExtern dsxt devSoft_DSXT; /* Allow anything table */

View File

@@ -6,7 +6,10 @@
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* drvSup.h Driver Support */
/** @file drvSup.h
*
* @brief Driver support routines.
*/
/*
* Author: Marty Kraimer
@@ -18,16 +21,38 @@
#include "errMdef.h"
typedef long (*DRVSUPFUN) (); /* ptr to driver support function*/
/** Driver entry table */
typedef struct typed_drvet {
/** Number of function pointers which follow. Must be >=2 */
long number;
/** Called from dbior() */
long (*report)(int lvl);
/** Called during iocInit() */
long (*init)(void);
/* Any further functions are driver-specific */
} typed_drvet;
#ifdef USE_TYPED_DRVET
typedef typed_drvet drvet;
#else
/* These interfaces may eventually get deprecated */
typedef long (*DRVSUPFUN) (); /* ptr to driver support function */
typedef struct drvet { /* driver entry table */
long number; /* number of support routines */
DRVSUPFUN report; /* print report */
DRVSUPFUN init; /* init support */
/* Any further functions are driver-specific */
} drvet;
typedef struct drvet { /* driver entry table */
long number; /*number of support routines*/
DRVSUPFUN report; /*print report*/
DRVSUPFUN init; /*init support*/
/*other functions are device dependent*/
}drvet;
#define DRVETNUMBER ( (sizeof(struct drvet) -sizeof(long))/sizeof(DRVSUPFUN) )
#endif /* USE_TYPED_DRVET */
#define S_drv_noDrvSup (M_drvSup| 1) /*SDR_DRVSUP: Driver support missing*/
#define S_drv_noDrvet (M_drvSup| 3) /*Missing driver support entry table*/

File diff suppressed because it is too large Load Diff

View File

@@ -34,10 +34,10 @@ be written to stdout unless the -o option is given.</p>
<dl>
<dt><tt>-V</tt></dt>
<dd>Verbose warnings; if this parameter is specified then any undefined
macro discovered in the template file which does not have an associated
default value is considered an error. An error message is generated, and
when msi terminates it will do so with an exit status of 2.</dd>
<dd>Verbose warnings; if this parameter is specified then any undefined or
recursive macros discovered in the template will be considered an error and
will be marked in the output file. An error message will be shown, and when
msi terminates it will do so with an exit status of 2.</dd>
<dt><tt>-g</tt></dt>
<dd>When this flag is given all macros defined in a substitution file will

View File

@@ -26,3 +26,4 @@ dbCore_SRCS += miscIocRegister.c
dbCore_SRCS += dlload.c
dbCore_SRCS += iocshRegisterCommon.c
miscIocRegister_CFLAGS_iOS = -DSYSTEM_UNAVAILABLE

View File

@@ -12,6 +12,9 @@ variable(asCaDebug,int)
# CA server debug flag (very verbose) range[0,5]
variable(CASDEBUG,int)
# Link parsing debug
variable(dbJLinkDebug,int)
# Static database access variables
variable(dbRecordsOnceOnly,int)
variable(dbRecordsAbcSorted,int)
@@ -19,8 +22,12 @@ variable(dbBptNotMonotonic,int)
variable(dbQuietMacroWarnings,int)
variable(dbConvertStrict,int)
# PUTF/RPRO tracing; set TPRO on records to trace
variable(dbAccessDebugPUTF,int)
# dbLoadTemplate settings
variable(dbTemplateMaxVars,int)
# Default number of parallel callback threads
variable(callbackParallelThreadsDefault,int)

View File

@@ -66,10 +66,12 @@ void miscIocRegister(void)
/* system -- escape to system command interpreter.
*
* Disabled by default, for security reasons. To enable this command, add
* Disabled by default for security reasons, not available on all OSs.
* To enable this command, add
* registrar(iocshSystemCommand)
* to an application dbd file.
* to an application dbd file, or include system.dbd
*/
#ifndef SYSTEM_UNAVAILABLE
static const iocshArg systemArg0 = { "command string",iocshArgString};
static const iocshArg * const systemArgs[] = {&systemArg0};
static const iocshFuncDef systemFuncDef = {"system",1,systemArgs};
@@ -77,12 +79,15 @@ static void systemCallFunc(const iocshArgBuf *args)
{
system(args[0].sval);
}
#endif
static void iocshSystemCommand(void)
{
#ifndef SYSTEM_UNAVAILABLE
if (system(NULL))
iocshRegister(&systemFuncDef, systemCallFunc);
else
#endif
errlogPrintf ("Can't register 'system' command -- no command interpreter available.\n");
}
epicsExportRegistrar(iocshSystemCommand);

View File

@@ -324,7 +324,7 @@ void rsrv_build_addr_lists(void)
#ifdef IP_MULTICAST_TTL
{
int ttl;
osiSockOptMcastTTL_t ttl;
long val;
if(envGetLongConfigParam(&EPICS_CA_MCAST_TTL, &val))
val =1;

View File

@@ -23,6 +23,7 @@
#include "dbDefs.h"
#include "dbAccess.h"
#include "dbConstLink.h"
#include "dbEvent.h"
#include "recGbl.h"
#include "devSup.h"
#include "cantProceed.h"
@@ -96,11 +97,15 @@ static long readLocked(struct link *pinp, void *dummy)
static long read_aai(aaiRecord *prec)
{
epicsUInt32 nord = prec->nord;
struct link *pinp = prec->simm == menuYesNoYES ? &prec->siol : &prec->inp;
long status = dbLinkDoLocked(pinp, readLocked, NULL);
if (status == S_db_noLSET)
status = readLocked(pinp, NULL);
if (!status && nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
return status;
}

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2002 Lawrence Berkeley Laboratory,The Control Systems
* Group, Systems Engineering Department
* 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.
\*************************************************************************/
/*
@@ -19,6 +19,7 @@
#include "alarm.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "recGbl.h"
#include "devSup.h"
#include "subArrayRecord.h"
@@ -101,6 +102,7 @@ static long read_sa(subArrayRecord *prec)
{
long status;
struct sart rt;
epicsUInt32 nord = prec->nord;
rt.nRequest = prec->indx + prec->nelm;
if (rt.nRequest > prec->malm)
@@ -123,8 +125,12 @@ static long read_sa(subArrayRecord *prec)
status = readLocked(&prec->inp, &rt);
}
if (!status && rt.nRequest > 0)
if (!status && rt.nRequest > 0) {
subset(prec, rt.nRequest);
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
}
return status;
}

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos 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.
\*************************************************************************/
/*
@@ -81,6 +81,7 @@ static long read_wf(waveformRecord *prec)
{
long status;
struct wfrt rt;
epicsUInt32 nord = prec->nord;
rt.nRequest = prec->nelm;
rt.ptime = (dbLinkIsConstant(&prec->tsel) &&
@@ -93,6 +94,8 @@ static long read_wf(waveformRecord *prec)
if (!status && rt.nRequest > 0) {
prec->nord = rt.nRequest;
prec->udf = FALSE;
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
}
return status;

View File

@@ -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.
#*************************************************************************
# This is a Makefile fragment, see src/std/Makefile.
@@ -13,6 +13,7 @@ DBD += links.dbd
dbRecStd_SRCS += lnkConst.c
dbRecStd_SRCS += lnkCalc.c
dbRecStd_SRCS += lnkState.c
dbRecStd_SRCS += lnkDebug.c
HTMLS += links.html

View File

@@ -13,6 +13,12 @@ The following additional link types are available in this release:
=item * L<Calc|/"Calculation Link calc">
=item * L<dbState|/"dbState Link state">
=item * L<Debug|/"Debug Link debug">
=item * L<Trace|/"Trace Link trace">
=back
=head2 Using JSON Links
@@ -31,15 +37,16 @@ database file syntax.
=cut
link(const, lnkConstIf)
=head3 Constant Link C<"const">
Constant links provide one or more values at link initalization time, but do not
return any data when their C<getValue()> routine is called. Most record types
support the use of constant links by calling C<recGblInitConstantLink()> at
record initialization, which results in the constant value being loaded into the
target field at that time.
Constant links are input links that provide literal values at link initalization
time, but do not return any data when their C<getValue()> routine is called.
Most record types support the use of constant links on their input links by
calling C<recGblInitConstantLink()> at record initialization, which results in
the constant value being loaded into the target field at that time.
Note that for most record types (the C<printf> and C<calcout> records are the
main exceptions) it is pointless to set an input link to a constant link at
@@ -70,14 +77,35 @@ converted to the desired double value at initialization, for example:
=cut
link(calc, lnkCalcIf)
=head3 Calculation Link C<"calc">
Calculation links can perform simple mathematical expressions on scalar
(double-precision floating-point) values obtained from other link types and
return a single double-precision floating-point result. The expressions are
evaluated by the EPICS Calc engine, and up to 12 inputs can be provided.
A calculation link is an input link that can evaluate mathematical expressions
on scalar (double-precision floating-point) values obtained from up to 12 child
input links, and returns a double-precision floating-point result. The
expression is evaluated by the EPICS Calc engine, and the result is returned as
the value of the link.
Two additional expressions may also be provided and are evaluated to determine
whether the record owning the link should be placed in alarm state. In both
cases the result of the main calculation is available to these expressions as
C<VAL> (attempts to assign to C<VAL> inside either expression will have no
lasting effect). If the C<major> expression evaluates to a non-zero value the
record will be placed in C<LINK/MAJOR> alarm. If not and the C<minor> expression
evaluates to non-zero the record will be placed in C<LINK/MINOR> alarm state.
A calculation link can also be an output link, with the scalar output value
being converted to a double and provided to the expression as C<VAL>. Up to 12
additional input links can also be read and provided to the expression as above.
The result of the calculation is forwarded to a child output link specified in
the link's C<out> parameter.
For an output link the main expression is actually optional; if not provided the
converted value will be forwarded to the output link unchanged. The two alarm
expressions may still be used to put the output link into alarm state as
described above.
=head4 Parameters
@@ -88,6 +116,7 @@ The link address is a JSON map with the following keys:
=item expr
The primary expression to be evaluated, given as a string.
This is optional for output links, required for input links.
=item major
@@ -104,6 +133,12 @@ to the inputs C<A>, C<B>, C<C>, ... C<L>. Each input argument may be either a
numeric literal or an embedded JSON link inside C<{}> braces. The same input
values are provided to the two alarm expressions as to the primary expression.
=item out
A JSON link inside C<{}> braces which specifies the destination of C<putValue>
operations after any expressions have been evaluated.
This key is required for output links, not used by input links.
=item units
An optional string specifying the engineering units for the result of the
@@ -129,3 +164,72 @@ atomically with the value of the input argument.
{calc: {expr:"A*B", args:[{db:"record.VAL"}, 1.5], prec:3}}
=cut
link(state, lnkStateIf)
=head3 dbState Link C<"state">
A dbState link is one that gets or puts a boolean value from/to a named global
flag as implemented by the dbState facility in C<dbstate.h>. The link type can
invert the sense of the dbState flag during the get or put if desired.
The value of the named flag is read or written at the time of the link I/O
operation. When reading a flag, the value returned by the link will be zero or
one converted to the requested data type. When writing to a flag the boolean
value of the data written is determined in the originating data type. All
strings are regarded as true other than C<""> and C<"0"> which are both false.
A link can be configured to invert the sense of the flag data by putting an
exclamation mark C<!> before the first character of the flag's name in the link
address.
These dbState flags can be accessed from the IOC Shell with various dbState
commands, and are also used by the C<"sync"> Channel-Access server-side filter
mechanism.
=head4 Parameters
The link takes a single parameter which must be a string, providing the name of
the dbState object, with an optional leading C<!> character to indicate that the
flag's value should be inverted. The dbState object will be created when the
link is initialized if it doesn't already exist.
=head4 Examples
{state:"redBeam"}
{state:"!simEnable"}
=cut
link(debug, lnkDebugIf)
variable(lnkDebug_debug, int)
=head3 Debug Link C<"debug">
The debug link type exists to enable debugging of other link types; it provides
no functionality itself other than to turn on the debug flag for the child link
that is its only parameter and pass all link operations down to that link.
=head4 Example
{debug:{state:"redBeam"}}
=cut
link(trace, lnkTraceIf)
=head3 Trace Link C<"trace">
The trace link type is a relative of the debug link type that also traces the
operation of its child link. At creation it turns on the debug flag of its child
link, then it prints the method arguments and return values of all link
operations before / after passing control down to the child link.
=head4 Example
{trace:{state:"redBeam"}}
=cut

View File

@@ -6,13 +6,9 @@
\*************************************************************************/
/* lnkCalc.c */
/* Current usage
* {calc:{expr:"A", args:[{...}, ...]}}
/* Usage
* {calc:{expr:"A*B", args:[{...}, ...], units:"mm"}}
* First link in 'args' is 'A', second is 'B', and so forth.
*
* TODO:
* Support setting individual input links instead of the args list.
* {calc:{expr:"K", K:{...}}}
*/
#include <string.h>
@@ -26,6 +22,7 @@
#include "epicsAssert.h"
#include "epicsString.h"
#include "epicsTypes.h"
#include "epicsTime.h"
#include "dbAccessDefs.h"
#include "dbCommon.h"
#include "dbConvertFast.h"
@@ -40,15 +37,14 @@
typedef long (*FASTCONVERT)();
#define IFDEBUG(n) if(clink->jlink.debug)
typedef struct calc_link {
jlink jlink; /* embedded object */
int nArgs;
short dbfType;
enum {
ps_init,
ps_expr, ps_major, ps_minor,
ps_args,
ps_args, ps_out,
ps_prec,
ps_units,
ps_time,
@@ -66,7 +62,9 @@ typedef struct calc_link {
char *units;
short tinp;
struct link inp[CALCPERFORM_NARGS];
struct link out;
double arg[CALCPERFORM_NARGS];
epicsTimeStamp time;
double val;
} calc_link;
@@ -77,19 +75,25 @@ static lset lnkCalc_lset;
static jlink* lnkCalc_alloc(short dbfType)
{
calc_link *clink = calloc(1, sizeof(struct calc_link));
calc_link *clink;
IFDEBUG(10)
printf("lnkCalc_alloc()\n");
if (dbfType == DBF_FWDLINK) {
errlogPrintf("lnkCalc: No support for forward links\n");
return NULL;
}
clink = calloc(1, sizeof(struct calc_link));
if (!clink) {
errlogPrintf("lnkCalc: calloc() failed.\n");
return NULL;
}
clink->nArgs = 0;
clink->dbfType = dbfType;
clink->pstate = ps_init;
clink->prec = 15; /* standard value for a double */
clink->tinp = -1;
IFDEBUG(10)
printf("lnkCalc_alloc -> calc@%p\n", clink);
return &clink->jlink;
}
@@ -98,12 +102,11 @@ static void lnkCalc_free(jlink *pjlink)
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
int i;
IFDEBUG(10)
printf("lnkCalc_free(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++)
dbJLinkFree(clink->inp[i].value.json.jlink);
dbJLinkFree(clink->out.value.json.jlink);
free(clink->expr);
free(clink->major);
free(clink->minor);
@@ -118,9 +121,6 @@ static jlif_result lnkCalc_integer(jlink *pjlink, long long num)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_integer(calc@%p, %lld)\n", clink, num);
if (clink->pstate == ps_prec) {
clink->prec = num;
return jlif_continue;
@@ -146,9 +146,6 @@ static jlif_result lnkCalc_double(jlink *pjlink, double num)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_double(calc@%p, %g)\n", clink, num);
if (clink->pstate != ps_args) {
return jlif_stop;
errlogPrintf("lnkCalc: Unexpected double %g\n", num);
@@ -171,9 +168,6 @@ static jlif_result lnkCalc_string(jlink *pjlink, const char *val, size_t len)
char *inbuf, *postbuf;
short err;
IFDEBUG(10)
printf("lnkCalc_string(calc@%p, \"%.*s\")\n", clink, (int) len, val);
if (clink->pstate == ps_units) {
clink->units = epicsStrnDup(val, len);
return jlif_continue;
@@ -181,7 +175,8 @@ static jlif_result lnkCalc_string(jlink *pjlink, const char *val, size_t len)
if (clink->pstate == ps_time) {
char tinp;
if (len != 1 || (tinp = toupper(val[0])) < 'A' || tinp > 'L') {
if (len != 1 || (tinp = toupper((int) val[0])) < 'A' || tinp > 'L') {
errlogPrintf("lnkCalc: Bad 'time' parameter \"%.*s\"\n", (int) len, val);
return jlif_stop;
}
@@ -234,11 +229,10 @@ static jlif_key_result lnkCalc_start_map(jlink *pjlink)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_start_map(calc@%p)\n", clink);
if (clink->pstate == ps_args)
return jlif_key_child_link;
return jlif_key_child_inlink;
if (clink->pstate == ps_out)
return jlif_key_child_outlink;
if (clink->pstate != ps_init) {
errlogPrintf("lnkCalc: Unexpected map\n");
@@ -252,10 +246,21 @@ static jlif_result lnkCalc_map_key(jlink *pjlink, const char *key, size_t len)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_map_key(calc@%p, \"%.*s\")\n", pjlink, (int) len, key);
/* FIXME: These errors messages are wrong when a key is duplicated.
* The key is known, we just don't allow it more than once.
*/
if (len == 4) {
if (len == 3) {
if (!strncmp(key, "out", len) &&
clink->dbfType == DBF_OUTLINK &&
clink->out.type == 0)
clink->pstate = ps_out;
else {
errlogPrintf("lnkCalc: Unknown key \"%.3s\"\n", key);
return jlif_stop;
}
}
else if (len == 4) {
if (!strncmp(key, "expr", len) && !clink->post_expr)
clink->pstate = ps_expr;
else if (!strncmp(key, "args", len) && !clink->nArgs)
@@ -293,13 +298,16 @@ static jlif_result lnkCalc_end_map(jlink *pjlink)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_end_map(calc@%p)\n", clink);
if (clink->pstate == ps_error)
return jlif_stop;
else if (!clink->post_expr) {
errlogPrintf("lnkCalc: no expression ('expr' key)\n");
else if (clink->dbfType == DBF_INLINK &&
!clink->post_expr) {
errlogPrintf("lnkCalc: No expression ('expr' key)\n");
return jlif_stop;
}
else if (clink->dbfType == DBF_OUTLINK &&
clink->out.type != JSON_LINK) {
errlogPrintf("lnkCalc: No output link ('out' key)\n");
return jlif_stop;
}
@@ -310,9 +318,6 @@ static jlif_result lnkCalc_start_array(jlink *pjlink)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_start_array(calc@%p)\n", clink);
if (clink->pstate != ps_args) {
errlogPrintf("lnkCalc: Unexpected array\n");
return jlif_stop;
@@ -325,9 +330,6 @@ static jlif_result lnkCalc_end_array(jlink *pjlink)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_end_array(calc@%p)\n", clink);
if (clink->pstate == ps_error)
return jlif_stop;
@@ -339,15 +341,27 @@ static void lnkCalc_end_child(jlink *parent, jlink *child)
calc_link *clink = CONTAINER(parent, struct calc_link, jlink);
struct link *plink;
if (clink->nArgs == CALCPERFORM_NARGS) {
dbJLinkFree(child);
errlogPrintf("lnkCalc: Too many input args, limit is %d\n",
CALCPERFORM_NARGS);
if (clink->pstate == ps_args) {
if (clink->nArgs == CALCPERFORM_NARGS) {
errlogPrintf("lnkCalc: Too many input args, limit is %d\n",
CALCPERFORM_NARGS);
goto errOut;
}
plink = &clink->inp[clink->nArgs++];
}
else if (clink->pstate == ps_out) {
plink = &clink->out;
}
else {
errlogPrintf("lnkCalc: Unexpected child link, parser state = %d\n",
clink->pstate);
errOut:
clink->pstate = ps_error;
dbJLinkFree(child);
return;
}
plink = &clink->inp[clink->nArgs++];
plink->type = JSON_LINK;
plink->value.json.string = NULL;
plink->value.json.jlink = child;
@@ -355,11 +369,6 @@ static void lnkCalc_end_child(jlink *parent, jlink *child)
static struct lset* lnkCalc_get_lset(const jlink *pjlink)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_get_lset(calc@%p)\n", pjlink);
return &lnkCalc_lset;
}
@@ -368,9 +377,6 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent)
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
int i;
IFDEBUG(10)
printf("lnkCalc_report(calc@%p)\n", clink);
printf("%*s'calc': \"%s\" = %.*g %s\n", indent, "",
clink->expr, clink->prec, clink->val,
clink->units ? clink->units : "");
@@ -388,9 +394,13 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent)
printf("%*s Minor expression: \"%s\"\n", indent, "",
clink->minor);
if (clink->tinp >= 0 && clink->tinp < clink->nArgs)
printf("%*s Timestamp input \"%c\"\n", indent, "",
clink->tinp + 'A');
if (clink->tinp >= 0) {
char timeStr[40];
epicsTimeToStrftime(timeStr, 40, "%Y-%m-%d %H:%M:%S.%09f",
&clink->time);
printf("%*s Timestamp input %c: %s\n", indent, "",
clink->tinp + 'A', timeStr);
}
for (i = 0; i < clink->nArgs; i++) {
struct link *plink = &clink->inp[i];
@@ -403,17 +413,20 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent)
if (child)
dbJLinkReport(child, level - 1, indent + 4);
}
if (clink->out.type == JSON_LINK) {
printf("%*s Output:\n", indent, "");
dbJLinkReport(clink->out.value.json.jlink, level - 1, indent + 4);
}
}
}
long lnkCalc_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx)
static long lnkCalc_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
int i;
IFDEBUG(10)
printf("lnkCalc_map_children(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i];
long status = dbJLinkMapChildren(child, rtn, ctx);
@@ -421,6 +434,10 @@ long lnkCalc_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx)
if (status)
return status;
}
if (clink->out.type == JSON_LINK) {
return dbJLinkMapChildren(&clink->out, rtn, ctx);
}
return 0;
}
@@ -432,9 +449,6 @@ static void lnkCalc_open(struct link *plink)
struct calc_link, jlink);
int i;
IFDEBUG(10)
printf("lnkCalc_open(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i];
@@ -442,6 +456,10 @@ static void lnkCalc_open(struct link *plink)
dbJLinkInit(child);
dbLoadLink(child, DBR_DOUBLE, &clink->arg[i]);
}
if (clink->out.type == JSON_LINK) {
dbJLinkInit(&clink->out);
}
}
static void lnkCalc_remove(struct dbLocker *locker, struct link *plink)
@@ -450,15 +468,16 @@ static void lnkCalc_remove(struct dbLocker *locker, struct link *plink)
struct calc_link, jlink);
int i;
IFDEBUG(10)
printf("lnkCalc_remove(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i];
dbRemoveLink(locker, child);
}
if (clink->out.type == JSON_LINK) {
dbRemoveLink(locker, &clink->out);
}
free(clink->expr);
free(clink->major);
free(clink->minor);
@@ -477,9 +496,6 @@ static int lnkCalc_isConn(const struct link *plink)
int connected = 1;
int i;
IFDEBUG(10)
printf("lnkCalc_isConn(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i];
@@ -488,37 +504,24 @@ static int lnkCalc_isConn(const struct link *plink)
connected = 0;
}
if (clink->out.type == JSON_LINK) {
struct link *child = &clink->out;
if (dbLinkIsVolatile(child) &&
!dbIsLinkConnected(child))
connected = 0;
}
return connected;
}
static int lnkCalc_getDBFtype(const struct link *plink)
{
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
IFDEBUG(10) {
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
printf("lnkCalc_getDBFtype(calc@%p)\n", clink);
}
return DBF_DOUBLE;
}
static long lnkCalc_getElements(const struct link *plink, long *nelements)
{
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
IFDEBUG(10) {
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
printf("lnkCalc_getElements(calc@%p, (%ld))\n",
clink, *nelements);
}
*nelements = 1;
return 0;
}
@@ -551,23 +554,22 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
long status;
FASTCONVERT conv = dbFastPutConvertRoutine[DBR_DOUBLE][dbrType];
IFDEBUG(10)
printf("lnkCalc_getValue(calc@%p, %d, ...)\n",
clink, dbrType);
/* Any link errors will trigger a LINK/INVALID alarm in the child link */
for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i];
long nReq = 1;
if (i == clink->tinp &&
dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime) {
struct lcvt vt = {&clink->arg[i], &prec->time};
if (i == clink->tinp) {
struct lcvt vt = {&clink->arg[i], &clink->time};
status = dbLinkDoLocked(child, readLocked, &vt);
if (status == S_db_noLSET)
status = readLocked(child, &vt);
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime) {
prec->time = clink->time;
}
}
else
dbGetLink(child, DBR_DOUBLE, &clink->arg[i], NULL, &nReq);
@@ -599,7 +601,7 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
}
}
if (!status && clink->post_minor) {
if (!status && !clink->sevr && clink->post_minor) {
double alval = clink->val;
status = calcPerform(clink->arg, &alval, clink->post_minor);
@@ -613,14 +615,79 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
return status;
}
static long lnkCalc_putValue(struct link *plink, short dbrType,
const void *pbuffer, long nRequest)
{
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
dbCommon *prec = plink->precord;
int i;
long status;
FASTCONVERT conv = dbFastGetConvertRoutine[dbrType][DBR_DOUBLE];
/* Any link errors will trigger a LINK/INVALID alarm in the child link */
for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i];
long nReq = 1;
if (i == clink->tinp) {
struct lcvt vt = {&clink->arg[i], &clink->time};
status = dbLinkDoLocked(child, readLocked, &vt);
if (status == S_db_noLSET)
status = readLocked(child, &vt);
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime) {
prec->time = clink->time;
}
}
else
dbGetLink(child, DBR_DOUBLE, &clink->arg[i], NULL, &nReq);
}
clink->stat = 0;
clink->sevr = 0;
/* Get the value being output as VAL */
status = conv(pbuffer, &clink->val, NULL);
if (!status && clink->post_expr)
status = calcPerform(clink->arg, &clink->val, clink->post_expr);
if (!status && clink->post_major) {
double alval = clink->val;
status = calcPerform(clink->arg, &alval, clink->post_major);
if (!status && alval) {
clink->stat = LINK_ALARM;
clink->sevr = MAJOR_ALARM;
recGblSetSevr(prec, clink->stat, clink->sevr);
}
}
if (!status && !clink->sevr && clink->post_minor) {
double alval = clink->val;
status = calcPerform(clink->arg, &alval, clink->post_minor);
if (!status && alval) {
clink->stat = LINK_ALARM;
clink->sevr = MINOR_ALARM;
recGblSetSevr(prec, clink->stat, clink->sevr);
}
}
if (!status) {
status = dbPutLink(&clink->out, DBR_DOUBLE, &clink->val, 1);
}
return status;
}
static long lnkCalc_getPrecision(const struct link *plink, short *precision)
{
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_getPrecision(calc@%p)\n", clink);
*precision = clink->prec;
return 0;
}
@@ -630,9 +697,6 @@ static long lnkCalc_getUnits(const struct link *plink, char *units, int len)
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_getUnits(calc@%p)\n", clink);
if (clink->units) {
strncpy(units, clink->units, --len);
units[len] = '\0';
@@ -648,9 +712,6 @@ static long lnkCalc_getAlarm(const struct link *plink, epicsEnum16 *status,
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_getAlarm(calc@%p)\n", clink);
if (status)
*status = clink->stat;
if (severity)
@@ -659,6 +720,19 @@ static long lnkCalc_getAlarm(const struct link *plink, epicsEnum16 *status,
return 0;
}
static long lnkCalc_getTimestamp(const struct link *plink, epicsTimeStamp *pstamp)
{
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
if (clink->tinp >= 0) {
*pstamp = clink->time;
return 0;
}
return -1;
}
static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
{
return rtn(plink, priv);
@@ -675,8 +749,8 @@ static lset lnkCalc_lset = {
lnkCalc_getValue,
NULL, NULL, NULL,
lnkCalc_getPrecision, lnkCalc_getUnits,
lnkCalc_getAlarm, NULL,
NULL, NULL,
lnkCalc_getAlarm, lnkCalc_getTimestamp,
lnkCalc_putValue, NULL,
NULL, doLocked
};
@@ -686,6 +760,6 @@ static jlif lnkCalcIf = {
lnkCalc_start_map, lnkCalc_map_key, lnkCalc_end_map,
lnkCalc_start_array, lnkCalc_end_array,
lnkCalc_end_child, lnkCalc_get_lset,
lnkCalc_report, lnkCalc_map_children
lnkCalc_report, lnkCalc_map_children, NULL
};
epicsExportAddress(jlif, lnkCalcIf);

View File

@@ -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.
\*************************************************************************/
/* lnkConst.c */
@@ -22,8 +22,6 @@
#include "epicsExport.h"
#define IFDEBUG(n) if (clink->jlink.debug)
typedef long (*FASTCONVERT)();
typedef struct const_link {
@@ -48,18 +46,23 @@ static lset lnkConst_lset;
static jlink* lnkConst_alloc(short dbfType)
{
const_link *clink = calloc(1, sizeof(*clink));
const_link *clink;
IFDEBUG(10)
printf("lnkConst_alloc()\n");
if (dbfType != DBF_INLINK) {
errlogPrintf("lnkConst: Only works with input links\n");
return NULL;
}
clink = calloc(1, sizeof(*clink));
if (!clink) {
errlogPrintf("lnkConst: calloc() failed.\n");
return NULL;
}
clink->type = s0;
clink->nElems = 0;
clink->value.pmem = NULL;
IFDEBUG(10)
printf("lnkConst_alloc -> const@%p\n", clink);
return &clink->jlink;
}
@@ -67,9 +70,6 @@ static void lnkConst_free(jlink *pjlink)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_free(const@%p) type=%d\n", pjlink, clink->type);
switch (clink->type) {
int i;
case ac40:
@@ -95,16 +95,13 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
const_link *clink = CONTAINER(pjlink, const_link, jlink);
int newElems = clink->nElems + 1;
IFDEBUG(10)
printf("lnkConst_integer(const@%p, %lld)\n", pjlink, num);
switch (clink->type) {
void *buf;
case s0:
clink->type = si64;
clink->value.scalar_integer = num;
IFDEBUG(12)
if (pjlink->debug)
printf(" si64 := %lld\n", num);
break;
@@ -118,7 +115,7 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
clink->value.pmem = buf;
clink->value.pintegers[clink->nElems] = num;
IFDEBUG(12)
if (pjlink->debug)
printf(" ai64 += %lld\n", num);
break;
@@ -129,7 +126,7 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
clink->value.pmem = buf;
clink->value.pdoubles[clink->nElems] = num;
IFDEBUG(12)
if (pjlink->debug)
printf(" af64 += %lld\n", num);
break;
@@ -146,10 +143,6 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
static jlif_result lnkConst_boolean(jlink *pjlink, int val)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_boolean(const@%p, %d)\n", pjlink, val);
return lnkConst_integer(pjlink, val);
}
@@ -158,9 +151,6 @@ static jlif_result lnkConst_double(jlink *pjlink, double num)
const_link *clink = CONTAINER(pjlink, const_link, jlink);
int newElems = clink->nElems + 1;
IFDEBUG(10)
printf("lnkConst_double(const@%p, %g)\n", pjlink, num);
switch (clink->type) {
epicsFloat64 *f64buf;
int i;
@@ -212,9 +202,6 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
const_link *clink = CONTAINER(pjlink, const_link, jlink);
int newElems = clink->nElems + 1;
IFDEBUG(10)
printf("lnkConst_string(const@%p, \"%.*s\")\n", clink, (int) len, val);
switch (clink->type) {
char **vec, *str;
@@ -262,9 +249,6 @@ static jlif_result lnkConst_start_array(jlink *pjlink)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_start_array(const@%p)\n", pjlink);
if (clink->type != s0) {
errlogPrintf("lnkConst: Embedded array value\n");
return jlif_stop;
@@ -276,21 +260,11 @@ static jlif_result lnkConst_start_array(jlink *pjlink)
static jlif_result lnkConst_end_array(jlink *pjlink)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_end_array(const@%p)\n", pjlink);
return jlif_continue;
}
static struct lset* lnkConst_get_lset(const jlink *pjlink)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_get_lset(const@%p)\n", pjlink);
return &lnkConst_lset;
}
@@ -318,9 +292,6 @@ static void lnkConst_report(const jlink *pjlink, int level, int indent)
};
const char * const dtype = type_names[clink->type & 3];
IFDEBUG(10)
printf("lnkConst_report(const@%p)\n", clink);
if (clink->type > a0) {
const char * const plural = clink->nElems > 1 ? "s" : "";
@@ -382,11 +353,6 @@ static void lnkConst_report(const jlink *pjlink, int level, int indent)
static void lnkConst_remove(struct dbLocker *locker, struct link *plink)
{
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_remove(const@%p)\n", clink);
lnkConst_free(plink->value.json.jlink);
}
@@ -395,55 +361,51 @@ static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
long status;
IFDEBUG(10)
printf("lnkConst_loadScalar(const@%p, %d, %p)\n",
clink, dbrType, pbuffer);
switch (clink->type) {
case si64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" si64 %lld\n", clink->value.scalar_integer);
status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
(&clink->value.scalar_integer, pbuffer, NULL);
break;
case sf64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" sf64 %g\n", clink->value.scalar_double);
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
(&clink->value.scalar_double, pbuffer, NULL);
break;
case sc40:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" sc40 '%s'\n", clink->value.scalar_string);
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.scalar_string, pbuffer, NULL);
break;
case ai64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]);
status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
(clink->value.pintegers, pbuffer, NULL);
break;
case af64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]);
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
(clink->value.pdoubles, pbuffer, NULL);
break;
case ac40:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.pstrings[0], pbuffer, NULL);
break;
default:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" Bad type %d\n", clink->type);
status = S_db_badField;
break;
@@ -458,27 +420,23 @@ static long lnkConst_loadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
const char *pstr;
IFDEBUG(10)
printf("lnkConst_loadLS(const@%p, %p, %d, %d)\n",
clink, pbuffer, size, *plen);
if(!size) return 0;
switch (clink->type) {
case sc40:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" sc40 '%s'\n", clink->value.scalar_string);
pstr = clink->value.scalar_string;
break;
case ac40:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
pstr = clink->value.pstrings[0];
break;
default:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" Bad type %d\n", clink->type);
return S_db_badField;
}
@@ -499,10 +457,6 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
FASTCONVERT conv;
long status;
IFDEBUG(10)
printf("lnkConst_loadArray(const@%p, %d, %p, (%ld))\n",
clink, dbrType, pbuffer, *pnReq);
if (nElems > *pnReq)
nElems = *pnReq;
@@ -510,28 +464,28 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
int i;
case si64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" si64 %lld\n", clink->value.scalar_integer);
status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
(&clink->value.scalar_integer, pdest, NULL);
break;
case sf64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" sf64 %g\n", clink->value.scalar_double);
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
(&clink->value.scalar_double, pdest, NULL);
break;
case sc40:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" sc40 '%s'\n", clink->value.scalar_string);
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.scalar_string, pbuffer, NULL);
break;
case ai64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]);
conv = dbFastPutConvertRoutine[DBF_INT64][dbrType];
for (i = 0; i < nElems; i++) {
@@ -542,7 +496,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
break;
case af64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]);
conv = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType];
for (i = 0; i < nElems; i++) {
@@ -553,7 +507,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
break;
case ac40:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
conv = dbFastPutConvertRoutine[DBF_STRING][dbrType];
for (i = 0; i < nElems; i++) {
@@ -564,7 +518,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
break;
default:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" Bad type %d\n", clink->type);
status = S_db_badField;
}
@@ -574,12 +528,6 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
static long lnkConst_getNelements(const struct link *plink, long *nelements)
{
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_getNelements(const@%p, (%ld))\n",
plink->value.json.jlink, *nelements);
*nelements = 0;
return 0;
}
@@ -587,13 +535,6 @@ static long lnkConst_getNelements(const struct link *plink, long *nelements)
static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_getValue(const@%p, %d, %p, ... (%ld))\n",
plink->value.json.jlink, dbrType, pbuffer,
pnRequest ? *pnRequest : 0);
if (pnRequest)
*pnRequest = 0;
return 0;
@@ -626,7 +567,6 @@ static jlif lnkConstIf = {
NULL, NULL, NULL,
lnkConst_start_array, lnkConst_end_array,
NULL, lnkConst_get_lset,
lnkConst_report, NULL
lnkConst_report, NULL, NULL
};
epicsExportAddress(jlif, lnkConstIf);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,230 @@
/*************************************************************************\
* Copyright (c) 2017 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.
\*************************************************************************/
/* lnkState.c */
/* Usage:
* {state:green}
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "alarm.h"
#include "dbDefs.h"
#include "errlog.h"
#include "epicsAssert.h"
#include "epicsString.h"
#include "epicsTypes.h"
#include "dbAccessDefs.h"
#include "dbCommon.h"
#include "dbConvertFast.h"
#include "dbLink.h"
#include "dbJLink.h"
#include "dbStaticLib.h"
#include "dbStaticPvt.h"
#include "dbState.h"
#include "recGbl.h"
#include "epicsExport.h"
typedef long (*FASTCONVERT)();
typedef struct state_link {
jlink jlink; /* embedded object */
char *name;
short val;
short invert;
dbStateId state;
} state_link;
static lset lnkState_lset;
/*************************** jlif Routines **************************/
static jlink* lnkState_alloc(short dbfType)
{
state_link *slink;
if (dbfType == DBF_FWDLINK) {
errlogPrintf("lnkState: DBF_FWDLINK not supported\n");
return NULL;
}
slink = calloc(1, sizeof(struct state_link));
if (!slink) {
errlogPrintf("lnkState: calloc() failed.\n");
return NULL;
}
slink->name = NULL;
slink->state = NULL;
slink->invert = 0;
slink->val = 0;
return &slink->jlink;
}
static void lnkState_free(jlink *pjlink)
{
state_link *slink = CONTAINER(pjlink, struct state_link, jlink);
free(slink->name);
free(slink);
}
static jlif_result lnkState_string(jlink *pjlink, const char *val, size_t len)
{
state_link *slink = CONTAINER(pjlink, struct state_link, jlink);
if (len > 1 && val[0] == '!') {
slink->invert = 1;
val++; len--;
}
slink->name = epicsStrnDup(val, len);
return jlif_continue;
}
static struct lset* lnkState_get_lset(const jlink *pjlink)
{
return &lnkState_lset;
}
static void lnkState_report(const jlink *pjlink, int level, int indent)
{
state_link *slink = CONTAINER(pjlink, struct state_link, jlink);
printf("%*s'state': \"%s\" = %s%s\n", indent, "",
slink->name, slink->invert ? "! " : "", slink->val ? "TRUE" : "FALSE");
}
/*************************** lset Routines **************************/
static void lnkState_open(struct link *plink)
{
state_link *slink = CONTAINER(plink->value.json.jlink,
struct state_link, jlink);
slink->state = dbStateCreate(slink->name);
}
static void lnkState_remove(struct dbLocker *locker, struct link *plink)
{
state_link *slink = CONTAINER(plink->value.json.jlink,
struct state_link, jlink);
free(slink->name);
free(slink);
plink->value.json.jlink = NULL;
}
static int lnkState_getDBFtype(const struct link *plink)
{
return DBF_SHORT;
}
static long lnkState_getElements(const struct link *plink, long *nelements)
{
*nelements = 1;
return 0;
}
static long lnkState_getValue(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
state_link *slink = CONTAINER(plink->value.json.jlink,
struct state_link, jlink);
FASTCONVERT conv = dbFastPutConvertRoutine[DBR_SHORT][dbrType];
slink->val = slink->invert ^ dbStateGet(slink->state);
return conv(&slink->val, pbuffer, NULL);
}
static long lnkState_putValue(struct link *plink, short dbrType,
const void *pbuffer, long nRequest)
{
state_link *slink = CONTAINER(plink->value.json.jlink,
struct state_link, jlink);
short val;
const char *pstr;
if (nRequest == 0)
return 0;
switch(dbrType) {
case DBR_CHAR:
case DBR_UCHAR:
val = !! *(const epicsInt8 *) pbuffer;
break;
case DBR_SHORT:
case DBR_USHORT:
val = !! *(const epicsInt16 *) pbuffer;
break;
case DBR_LONG:
case DBR_ULONG:
val = !! *(const epicsInt32 *) pbuffer;
break;
case DBR_INT64:
case DBR_UINT64:
val = !! *(const epicsInt64 *) pbuffer;
break;
case DBR_FLOAT:
val = !! *(const epicsFloat32 *) pbuffer;
break;
case DBR_DOUBLE:
val = !! *(const epicsFloat64 *) pbuffer;
break;
case DBR_STRING: /* Only "" and "0" are FALSE */
pstr = (const char *) pbuffer;
val = (pstr[0] != 0) && ((pstr[0] != '0') || (pstr[1] != 0));
break;
default:
return S_db_badDbrtype;
}
slink->val = val;
val ^= slink->invert;
(val ? dbStateSet : dbStateClear)(slink->state);
return 0;
}
/************************* Interface Tables *************************/
static lset lnkState_lset = {
0, 0, /* not constant, always connected */
lnkState_open, lnkState_remove,
NULL, NULL, NULL,
NULL, lnkState_getDBFtype, lnkState_getElements,
lnkState_getValue,
NULL, NULL, NULL,
NULL, NULL,
NULL, NULL,
lnkState_putValue, NULL,
NULL, NULL
};
static jlif lnkStateIf = {
"state", lnkState_alloc, lnkState_free,
NULL, NULL, NULL, NULL, lnkState_string,
NULL, NULL, NULL,
NULL, NULL,
NULL, lnkState_get_lset,
lnkState_report, NULL, NULL
};
epicsExportAddress(jlif, lnkStateIf);

View File

@@ -2,7 +2,7 @@
* Copyright (c) 2002 Southeastern Universities Research Association, as
* Operator of Thomas Jefferson National Accelerator Facility.
* 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.
\*************************************************************************/
/* recAai.c */
@@ -11,7 +11,7 @@
* Original Author: Dave Barker
*
* C E B A F
*
*
* Continuous Electron Beam Accelerator Facility
* Newport News, Virginia, USA.
*
@@ -225,10 +225,14 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
static long put_array_info(DBADDR *paddr, long nNew)
{
aaiRecord *prec = (aaiRecord *)paddr->precord;
epicsUInt32 nord = prec->nord;
prec->nord = nNew;
if (prec->nord > prec->nelm)
prec->nord = prec->nelm;
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
return 0;
}
@@ -241,7 +245,7 @@ static long get_units(DBADDR *paddr, char *units)
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM)
break;
break;
case indexof(HOPR):
case indexof(LOPR):
strncpy(units,prec->egu,DB_UNITS_SIZE);
@@ -336,33 +340,22 @@ static void monitor(aaiRecord *prec)
static long readValue(aaiRecord *prec)
{
struct aaidset *pdset = (struct aaidset *) prec->dset;
long status = 0;
long status;
if (!prec->pact) {
status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
if (status) return status;
}
/* NB: Device support must post updates to NORD */
switch (prec->simm) {
case menuYesNoNO:
status = pdset->read_aai(prec);
break;
if (prec->pact)
goto do_read;
case menuYesNoYES: {
status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm,
&prec->simm, &prec->siml);
if (status)
return status;
if (prec->simm == menuYesNoYES) {
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
if (prec->pact || (prec->sdly < 0.)) {
/* Device suport is responsible for buffer
which might be read-only so we may not be
allowed to call dbGetLink on it.
Maybe also device support has an advanced
simulation mode.
Thus call device now.
Reading through SIOL is handled in Soft Channel Device Support
*/
status = pdset->read_aai(prec);
prec->pact = FALSE;
} else { /* !prec->pact && delay >= 0. */
if (prec->sdly >= 0) {
CALLBACK *pvt = prec->simpvt;
if (!pvt) {
pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
@@ -370,14 +363,14 @@ static long readValue(aaiRecord *prec)
}
if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
prec->pact = TRUE;
return 0;
}
break;
}
default:
else if (prec->simm != menuYesNoNO) {
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
status = -1;
return -1;
}
return status;
do_read:
return pdset->read_aai(prec);
}

View File

@@ -2,7 +2,7 @@
* Copyright (c) 2002 Southeastern Universities Research Association, as
* Operator of Thomas Jefferson National Accelerator Facility.
* 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.
\*************************************************************************/
/* recAao.c */
@@ -11,7 +11,7 @@
* Original Author: Dave Barker
*
* C E B A F
*
*
* Continuous Electron Beam Accelerator Facility
* Newport News, Virginia, USA.
*
@@ -225,10 +225,14 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
static long put_array_info(DBADDR *paddr, long nNew)
{
aaoRecord *prec = (aaoRecord *)paddr->precord;
epicsUInt32 nord = prec->nord;
prec->nord = nNew;
if (prec->nord > prec->nelm)
prec->nord = prec->nelm;
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
return 0;
}
@@ -241,7 +245,7 @@ static long get_units(DBADDR *paddr, char *units)
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM)
break;
break;
case indexof(HOPR):
case indexof(LOPR):
strncpy(units,prec->egu,DB_UNITS_SIZE);

View File

@@ -4,12 +4,12 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos 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.
\*************************************************************************/
/*
* Original Author: Bob Dalesio
* Date: 7-14-89
* Date: 7-14-89
*/
#include <stddef.h>
@@ -439,12 +439,16 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
static long put_array_info(DBADDR *paddr, long nNew)
{
compressRecord *prec = (compressRecord *) paddr->precord;
epicsUInt32 nuse = prec->nuse;
if (prec->balg == bufferingALG_FIFO)
prec->off = (prec->off + nNew) % prec->nsam;
prec->nuse += nNew;
if (prec->nuse > prec->nsam)
prec->nuse = prec->nsam;
if (nuse != prec->nuse)
db_post_events(prec, &prec->nuse, DBE_VALUE | DBE_LOG);
return 0;
}

View File

@@ -2,17 +2,17 @@
* Copyright (c) 2002 Lawrence Berkeley Laboratory,The Control Systems
* Group, Systems Engineering Department
* 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.
\*************************************************************************/
/* recSubArray.c - Record Support Routines for SubArray records
/* recSubArray.c - Record Support Routines for SubArray records
*
*
* Author: Carl Lionberger
* Date: 090293
*
* NOTES:
* Derived from waveform record.
* Derived from waveform record.
* Modification Log:
* -----------------
*/
@@ -126,7 +126,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
}
if (pdset->init_record)
return (*pdset->init_record)(prec);
return pdset->init_record(prec);
return 0;
}
@@ -194,11 +194,14 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
static long put_array_info(DBADDR *paddr, long nNew)
{
subArrayRecord *prec = (subArrayRecord *) paddr->precord;
epicsUInt32 nord = prec->nord;
if (nNew > prec->malm)
nNew = prec->malm;
prec->nord = nNew;
if (prec->nord > prec->malm)
prec->nord = prec->malm;
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
return 0;
}
@@ -211,7 +214,7 @@ static long get_units(DBADDR *paddr, char *units)
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM)
break;
break;
case indexof(HOPR):
case indexof(LOPR):
strncpy(units,prec->egu,DB_UNITS_SIZE);
@@ -321,4 +324,3 @@ static long readValue(subArrayRecord *prec)
return status;
}

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos 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.
\*************************************************************************/
/* recWaveform.c - Record Support Routines for Waveform records */
@@ -205,12 +205,14 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
static long put_array_info(DBADDR *paddr, long nNew)
{
waveformRecord *prec = (waveformRecord *) paddr->precord;
epicsUInt32 nord = prec->nord;
prec->nord = nNew;
if (prec->nord > prec->nelm)
prec->nord = prec->nelm;
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
return 0;
}
@@ -223,7 +225,7 @@ static long get_units(DBADDR *paddr, char *units)
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM)
break;
break;
case indexof(HOPR):
case indexof(LOPR):
strncpy(units,prec->egu,DB_UNITS_SIZE);
@@ -346,15 +348,18 @@ static long readValue(waveformRecord *prec)
case menuYesNoYES: {
long nRequest = prec->nelm;
epicsUInt32 nord = prec->nord;
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
if (prec->pact || (prec->sdly < 0.)) {
status = dbGetLink(&prec->siol, prec->ftvl, prec->bptr, 0, &nRequest);
if (status == 0) prec->udf = FALSE;
/* nord set only for db links: needed for old db_access */
if (status == 0)
prec->udf = FALSE;
if (!dbLinkIsConstant(&prec->siol)) {
prec->nord = nRequest;
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
}
prec->pact = FALSE;
} else { /* !prec->pact && delay >= 0. */

View File

@@ -1,5 +1,4 @@
eval 'exec perl -S $0 ${1+"$@"}' # -*- Mode: perl -*-
if $running_under_some_shell;
#!/usr/bin/env perl
#*************************************************************************
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.