Merged Michael's link-parsing branch
This commit is contained in:
+46
-19
@@ -55,6 +55,7 @@
|
||||
#include "dbScan.h"
|
||||
#include "dbServer.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbStaticPvt.h"
|
||||
#include "devSup.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "link.h"
|
||||
@@ -935,15 +936,17 @@ devSup* dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset) {
|
||||
static long dbPutFieldLink(DBADDR *paddr,
|
||||
short dbrType, const void *pbuffer, long nRequest)
|
||||
{
|
||||
dbLinkInfo link_info;
|
||||
DBADDR *pdbaddr = NULL;
|
||||
dbCommon *precord = paddr->precord;
|
||||
dbFldDes *pfldDes = paddr->pfldDes;
|
||||
long special = paddr->special;
|
||||
struct link *plink = (struct link *)paddr->pfield;
|
||||
const char *pstring = (const char *)pbuffer;
|
||||
DBENTRY dbEntry;
|
||||
struct dsxt *old_dsxt = NULL;
|
||||
struct dset *new_dset = NULL;
|
||||
struct dsxt *new_dsxt = NULL;
|
||||
devSup *new_devsup = NULL;
|
||||
long status;
|
||||
int isDevLink;
|
||||
short scan;
|
||||
@@ -962,31 +965,55 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
return S_db_badDbrtype;
|
||||
}
|
||||
|
||||
dbInitEntry(pdbbase, &dbEntry);
|
||||
status = dbFindRecord(&dbEntry, precord->name);
|
||||
if (!status) status = dbFindField(&dbEntry, pfldDes->name);
|
||||
if (status) goto finish;
|
||||
status = dbParseLink(pstring, pfldDes->field_type, &link_info);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (link_info.ltype == PV_LINK &&
|
||||
(link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) {
|
||||
DBADDR tempaddr;
|
||||
|
||||
if (dbNameToAddr(link_info.target, &tempaddr)==0) {
|
||||
/* This will become a DB link. */
|
||||
pdbaddr = malloc(sizeof(*pdbaddr));
|
||||
if (!pdbaddr) {
|
||||
status = S_db_noMemory;
|
||||
goto cleanup;
|
||||
}
|
||||
*pdbaddr = tempaddr; /* struct copy */
|
||||
}
|
||||
}
|
||||
|
||||
isDevLink = ellCount(&precord->rdes->devList) > 0 &&
|
||||
(strcmp(pfldDes->name, "INP") == 0 ||
|
||||
strcmp(pfldDes->name, "OUT") == 0);
|
||||
pfldDes->isDevLink;
|
||||
|
||||
dbLockSetGblLock();
|
||||
dbLockSetRecordLock(precord);
|
||||
if (pdbaddr)
|
||||
dbLockSetRecordLock(pdbaddr->precord);
|
||||
|
||||
scan = precord->scan;
|
||||
|
||||
if (isDevLink) {
|
||||
devSup *pdevSup = dbDTYPtoDevSup(precord->rdes, precord->dtyp);
|
||||
if (pdevSup) {
|
||||
new_dset = pdevSup->pdset;
|
||||
new_dsxt = pdevSup->pdsxt;
|
||||
new_devsup = dbDTYPtoDevSup(precord->rdes, precord->dtyp);
|
||||
if (new_devsup) {
|
||||
new_dset = new_devsup->pdset;
|
||||
new_dsxt = new_devsup->pdsxt;
|
||||
}
|
||||
}
|
||||
|
||||
if (dbCanSetLink(plink, &link_info, new_devsup)) {
|
||||
/* link type mis-match prevents assignment */
|
||||
status = S_dbLib_badField;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (isDevLink) {
|
||||
if (precord->dset) {
|
||||
pdevSup = dbDSETtoDevSup(precord->rdes, precord->dset);
|
||||
if (pdevSup)
|
||||
old_dsxt = pdevSup->pdsxt;
|
||||
devSup *old_devsup = dbDSETtoDevSup(precord->rdes, precord->dset);
|
||||
|
||||
if (old_devsup)
|
||||
old_dsxt = old_devsup->pdsxt;
|
||||
}
|
||||
|
||||
if (new_dsxt == NULL ||
|
||||
@@ -1012,7 +1039,7 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
switch (plink->type) { /* Old link type */
|
||||
case DB_LINK:
|
||||
case CA_LINK:
|
||||
dbRemoveLink(plink);
|
||||
dbRemoveLink(plink);
|
||||
break;
|
||||
|
||||
case PV_LINK:
|
||||
@@ -1032,7 +1059,7 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
|
||||
if (special) status = dbPutSpecial(paddr, 0);
|
||||
|
||||
if (!status) status = dbPutString(&dbEntry, pstring);
|
||||
if (!status) status = dbSetLink(plink, &link_info, new_devsup);
|
||||
|
||||
if (!status && special) status = dbPutSpecial(paddr, 1);
|
||||
|
||||
@@ -1059,7 +1086,7 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
|
||||
switch (plink->type) { /* New link type */
|
||||
case PV_LINK:
|
||||
dbAddLink(precord, plink, pfldDes->field_type);
|
||||
dbAddLink(precord, plink, pfldDes->field_type, pdbaddr);
|
||||
break;
|
||||
|
||||
case CONSTANT:
|
||||
@@ -1090,8 +1117,8 @@ postScanEvent:
|
||||
db_post_events(precord, &precord->scan, DBE_VALUE | DBE_LOG);
|
||||
unlock:
|
||||
dbLockSetGblUnlock();
|
||||
finish:
|
||||
dbFinishEntry(&dbEntry);
|
||||
cleanup:
|
||||
free(link_info.target);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
+12
-26
@@ -144,26 +144,6 @@ static long dbDbInitLink(struct link *plink, short dbfType)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbAddLink(struct link *plink, short dbfType)
|
||||
{
|
||||
DBADDR dbaddr;
|
||||
long status;
|
||||
DBADDR *pdbAddr;
|
||||
|
||||
status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
plink->type = DB_LINK;
|
||||
pdbAddr = dbCalloc(1, sizeof(struct dbAddr));
|
||||
*pdbAddr = dbaddr; /* structure copy */
|
||||
plink->value.pv_link.pvt = pdbAddr;
|
||||
|
||||
dbLockSetRecordLock(pdbAddr->precord);
|
||||
dbLockSetMerge(plink->value.pv_link.precord, pdbAddr->precord);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dbDbRemoveLink(struct link *plink)
|
||||
{
|
||||
free(plink->value.pv_link.pvt);
|
||||
@@ -400,7 +380,7 @@ static void dbDbScanFwdLink(struct link *plink)
|
||||
dbScanPassive(precord, paddr->precord);
|
||||
}
|
||||
|
||||
lset dbDb_lset = { dbDbInitLink, dbDbAddLink, NULL, dbDbRemoveLink,
|
||||
lset dbDb_lset = { dbDbRemoveLink,
|
||||
dbDbIsLinkConnected, dbDbGetDBFtype, dbDbGetElements, dbDbGetValue,
|
||||
dbDbGetControlLimits, dbDbGetGraphicLimits, dbDbGetAlarmLimits,
|
||||
dbDbGetPrecision, dbDbGetUnits, dbDbGetAlarm, dbDbGetTimeStamp,
|
||||
@@ -442,17 +422,23 @@ void dbInitLink(struct dbCommon *precord, struct link *plink, short dbfType)
|
||||
}
|
||||
}
|
||||
|
||||
void dbAddLink(struct dbCommon *precord, struct link *plink, short dbfType)
|
||||
void dbAddLink(struct dbCommon *precord, struct link *plink, short dbfType, DBADDR *ptargetaddr)
|
||||
{
|
||||
plink->value.pv_link.precord = precord;
|
||||
|
||||
if (plink == &precord->tsel)
|
||||
recGblTSELwasModified(plink);
|
||||
|
||||
if (!(plink->value.pv_link.pvlMask & (pvlOptCA | pvlOptCP | pvlOptCPP))) {
|
||||
/* Can we make it a DB link? */
|
||||
if (!dbDbAddLink(plink, dbfType))
|
||||
return;
|
||||
if (ptargetaddr) {
|
||||
/* make a DB link */
|
||||
|
||||
plink->type = DB_LINK;
|
||||
plink->value.pv_link.pvt = ptargetaddr;
|
||||
|
||||
/* target record is already locked in dbPutFieldLink() */
|
||||
dbLockSetMerge(plink->value.pv_link.precord, ptargetaddr->precord);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make it a CA link */
|
||||
|
||||
+2
-4
@@ -20,15 +20,13 @@
|
||||
#include "shareLib.h"
|
||||
#include "epicsTypes.h"
|
||||
#include "epicsTime.h"
|
||||
#include "dbAddr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct lset {
|
||||
long (*initLink)(struct link *plink, short dbfType);
|
||||
long (*addLink)(struct link *plink, short dbfType);
|
||||
long (*loadLink)(struct link *plink, short dbrType, void *pbuffer);
|
||||
void (*removeLink)(struct link *plink);
|
||||
int (*isLinkConnected)(const struct link *plink);
|
||||
int (*getDBFtype)(const struct link *plink);
|
||||
@@ -55,7 +53,7 @@ typedef struct lset {
|
||||
epicsShareFunc void dbInitLink(struct dbCommon *precord, struct link *plink,
|
||||
short dbfType);
|
||||
epicsShareFunc void dbAddLink(struct dbCommon *precord, struct link *plink,
|
||||
short dbfType);
|
||||
short dbfType, DBADDR *ptargetaddr);
|
||||
epicsShareFunc long dbLoadLink(struct link *plink, short dbrType,
|
||||
void *pbuffer);
|
||||
epicsShareFunc void dbRemoveLink(struct link *plink);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "dbAccess.h"
|
||||
#include "registry.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbStaticPvt.h"
|
||||
#include "osiFileName.h"
|
||||
#include "dbmf.h"
|
||||
#include "errlog.h"
|
||||
@@ -28,8 +29,125 @@
|
||||
|
||||
#include "testMain.h"
|
||||
|
||||
static
|
||||
int testStrcmp(int expect, const char *A, const char *B) {
|
||||
static const char op[] = "<=>";
|
||||
int ret = strcmp(A,B);
|
||||
testOk(ret==expect, "\"%s\" %c= \"%s\"",
|
||||
A, op[expect+1], B);
|
||||
return ret==expect;
|
||||
}
|
||||
|
||||
void dbTestIoc_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
#define TEST_CONSTANT(SET, EXPECT) {SET, {CONSTANT, EXPECT}}
|
||||
#define TEST_PV_LINK(SET, PV, MOD) {SET, {PV_LINK, PV, MOD}}
|
||||
#define TEST_HW(SET, TYPE, ID, PARM, ...) {SET, {TYPE, PARM, 0, ID, {__VA_ARGS__}}}
|
||||
|
||||
static const struct testParseDataT {
|
||||
const char * const str;
|
||||
dbLinkInfo info;
|
||||
} testParseData[] = {
|
||||
TEST_CONSTANT("", ""),
|
||||
TEST_CONSTANT("0.1", "0.1"),
|
||||
TEST_CONSTANT(" 0.2\t ", "0.2"),
|
||||
|
||||
TEST_PV_LINK("0.1a", "0.1a", 0),
|
||||
TEST_PV_LINK(" hello ", "hello", 0),
|
||||
TEST_PV_LINK(" hellox MSI", "hellox", pvlOptMSI),
|
||||
TEST_PV_LINK(" world MSICP", "world", pvlOptMSI|pvlOptCP),
|
||||
|
||||
TEST_HW("#C14 S145 @testing", VME_IO, "CS", "testing", 14, 145),
|
||||
TEST_HW("#B11 C12 N13 A14 F15 @cparam", CAMAC_IO, "BCNAF", "cparam", 11, 12, 13, 14, 15),
|
||||
TEST_HW(" #B111 C112 N113 @cparam", CAMAC_IO, "BCN", "cparam", 111, 112, 113),
|
||||
TEST_HW(" @hello world ", INST_IO, "", "hello world"),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static void testLinkParse(void)
|
||||
{
|
||||
const struct testParseDataT *td = testParseData;
|
||||
dbLinkInfo info;
|
||||
testDiag("link parsing");
|
||||
testdbPrepare();
|
||||
|
||||
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
|
||||
|
||||
dbTestIoc_registerRecordDeviceDriver(pdbbase);
|
||||
|
||||
testdbReadDatabase("dbPutLinkTest.db", NULL, NULL);
|
||||
|
||||
eltc(0);
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
|
||||
for(;td->str; td++) {
|
||||
int i, N;
|
||||
testDiag("Parse \"%s\"", td->str);
|
||||
testOk1(dbParseLink(td->str, DBF_INLINK, &info)==0);
|
||||
testOk1(info.ltype==td->info.ltype);
|
||||
if(td->info.target)
|
||||
testStrcmp(0, info.target, td->info.target);
|
||||
if(info.ltype==td->info.ltype) {
|
||||
switch(info.ltype) {
|
||||
case PV_LINK:
|
||||
testOk1(info.modifiers==td->info.modifiers);
|
||||
break;
|
||||
case VME_IO:
|
||||
testStrcmp(0, info.hwid, td->info.hwid);
|
||||
N = strlen(td->info.hwid);
|
||||
for(i=0; i<N; i++)
|
||||
testOk(info.hwnums[i]==td->info.hwnums[i], "%d == %d",
|
||||
info.hwnums[i], td->info.hwnums[i]);
|
||||
}
|
||||
}
|
||||
free(info.target);
|
||||
}
|
||||
|
||||
testIocShutdownOk();
|
||||
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
static const char *testParseFailData[] = {
|
||||
"#",
|
||||
"#S",
|
||||
"#ABC",
|
||||
"#A0 B",
|
||||
"#A0 B @",
|
||||
"#A0 B C @",
|
||||
"#R1 M2 D3 E4 @oops", /* RF_IO has no parm */
|
||||
"#C1 S2", /* VME_IO needs parm */
|
||||
NULL
|
||||
};
|
||||
|
||||
static void testLinkFailParse(void)
|
||||
{
|
||||
const char * const *td = testParseFailData;
|
||||
dbLinkInfo info;
|
||||
testDiag("link parsing of invalid input");
|
||||
testdbPrepare();
|
||||
|
||||
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
|
||||
|
||||
dbTestIoc_registerRecordDeviceDriver(pdbbase);
|
||||
|
||||
testdbReadDatabase("dbPutLinkTest.db", NULL, NULL);
|
||||
|
||||
eltc(0);
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
|
||||
for(;*td; td++) {
|
||||
testDiag("Expect failure \"%s\"", *td);
|
||||
testOk1(dbParseLink(*td, DBF_INLINK, &info)==S_dbLib_badField);
|
||||
}
|
||||
|
||||
testIocShutdownOk();
|
||||
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
static const struct testDataT {
|
||||
const char * const linkstring;
|
||||
short linkType;
|
||||
@@ -39,6 +157,7 @@ static const struct testDataT {
|
||||
{"", CONSTANT, 0},
|
||||
{"0", CONSTANT, 0},
|
||||
{"42", CONSTANT, 0},
|
||||
{"0x1", CONSTANT, 0},
|
||||
|
||||
{"x1", DB_LINK, 0, "x1 NPP NMS"},
|
||||
{"x1.VAL", DB_LINK, 0, "x1.VAL NPP NMS"},
|
||||
@@ -77,17 +196,17 @@ static void testCADBSet(void)
|
||||
prec = (xRecord*)testdbRecordPtr("x1");
|
||||
plink = &prec->lnk;
|
||||
|
||||
for(;td->linkstring;td++) {
|
||||
for (;td->linkstring;td++) {
|
||||
testDiag("x1.LNK <- \"%s\"", td->linkstring);
|
||||
|
||||
testdbPutFieldOk("x1.LNK", DBF_STRING, td->linkstring);
|
||||
if(td->linkback)
|
||||
if (td->linkback)
|
||||
testdbGetFieldEqual("x1.LNK", DBF_STRING, td->linkback);
|
||||
else
|
||||
testdbGetFieldEqual("x1.LNK", DBF_STRING, td->linkstring);
|
||||
testOk1(plink->type==td->linkType);
|
||||
|
||||
if(plink->type==td->linkType) {
|
||||
if (plink->type==td->linkType) {
|
||||
switch(td->linkType) {
|
||||
case CONSTANT:
|
||||
if(plink->value.constantStr)
|
||||
@@ -327,7 +446,7 @@ static void testLinkInitFail(void)
|
||||
testOk1(plink->type==VME_IO);
|
||||
testOk1(plink->value.vmeio.parm!=NULL);
|
||||
|
||||
testdbGetFieldEqual("eVME_IO2.INP", DBR_STRING, "#C200 S0 @");
|
||||
testdbGetFieldEqual("eVME_IO2.INP", DBR_STRING, "#C0 S0 @");
|
||||
|
||||
prec = (xRecord*)testdbRecordPtr("eVME_IO2");
|
||||
plink = &prec->inp;
|
||||
@@ -364,9 +483,8 @@ static void testLinkFail(void)
|
||||
/* INST_IO doesn't accept empty string */
|
||||
testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, "");
|
||||
|
||||
/* INST_IO accepts invalid input as empty string */
|
||||
testdbPutFieldOk("rINST_IO.INP", DBR_STRING, "abc");
|
||||
testdbGetFieldEqual("rINST_IO.INP", DBR_STRING, "@");
|
||||
/* INST_IO doesn't accept empty string */
|
||||
testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, "abc");
|
||||
|
||||
/* syntax errors */
|
||||
testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "#S201 C200 @another VME_IO");
|
||||
@@ -387,7 +505,9 @@ static void testLinkFail(void)
|
||||
|
||||
MAIN(dbPutLinkTest)
|
||||
{
|
||||
testPlan(200);
|
||||
testPlan(251);
|
||||
testLinkParse();
|
||||
testLinkFailParse();
|
||||
testCADBSet();
|
||||
testHWInitSet();
|
||||
testHWMod();
|
||||
|
||||
@@ -76,8 +76,9 @@ typedef struct dbFldDes{ /* field description */
|
||||
short indRecordType; /*within dbRecordType.papFldDes */
|
||||
short special; /*Special processing requirements */
|
||||
dbfType field_type; /*Field type as defined in dbFldTypes.h */
|
||||
unsigned int process_passive:1;/*should dbPutField process passive */
|
||||
unsigned int prop:1;/*field is a metadata, post DBE_PROPERTY on change*/
|
||||
unsigned int process_passive:1;/*should dbPutField process passive */
|
||||
unsigned int prop:1;/*field is a metadata, post DBE_PROPERTY on change*/
|
||||
unsigned int isDevLink:1; /* true for INP/OUT fields */
|
||||
ctType base; /*base for integer to string conversions*/
|
||||
short promptgroup; /*prompt, i.e. gui group */
|
||||
short interest; /*interest level */
|
||||
|
||||
@@ -486,6 +486,8 @@ static void dbRecordtypeFieldHead(char *name,char *type)
|
||||
allocTemp(pdbFldDes);
|
||||
pdbFldDes->name = epicsStrDup(name);
|
||||
pdbFldDes->as_level = ASL1;
|
||||
pdbFldDes->isDevLink = strcmp(pdbFldDes->name, "INP")==0 ||
|
||||
strcmp(pdbFldDes->name, "OUT")==0;
|
||||
for(i=0; i<DBF_NTYPES; i++) {
|
||||
if(strcmp(type,pamapdbfType[i].strvalue)==0) {
|
||||
pdbFldDes->field_type = pamapdbfType[i].value;
|
||||
|
||||
+361
-465
@@ -45,6 +45,8 @@
|
||||
#include "link.h"
|
||||
#include "special.h"
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
int dbStaticDebug = 0;
|
||||
static char *pNullString = "";
|
||||
#define messagesize 100
|
||||
@@ -85,12 +87,9 @@ static int mapDBFtoDCT[DBF_NOACCESS+1] = {
|
||||
/*forward references for private routines*/
|
||||
static FILE *openOutstream(const char *filename);
|
||||
static void finishOutstream(FILE *stream);
|
||||
static long setLinkType(DBENTRY *pdbentry);
|
||||
static long putParmString(char **pparm,const char *pstring);
|
||||
static void entryErrMessage(DBENTRY *pdbentry,long status,char *mess);
|
||||
static void zeroDbentry(DBENTRY *pdbentry);
|
||||
static char *getpMessage(DBENTRY *pdbentry);
|
||||
static long putPvLink(DBENTRY *pdbentry,short pvlMask,const char *pvname);
|
||||
static long dbAddOnePath (DBBASE *pdbbase, const char *path, unsigned length);
|
||||
|
||||
/* internal routines*/
|
||||
@@ -115,103 +114,6 @@ static void finishOutstream(FILE *stream)
|
||||
}
|
||||
}
|
||||
|
||||
static long setLinkType(DBENTRY *pdbentry)
|
||||
{
|
||||
DBENTRY dbEntry;
|
||||
dbRecordType *precordType;
|
||||
devSup *pdevSup;
|
||||
DBLINK *plink;
|
||||
long status=0;
|
||||
int link_type,ind,type;
|
||||
|
||||
dbCopyEntryContents(pdbentry, &dbEntry);
|
||||
status = dbFindField(&dbEntry, "DTYP");
|
||||
if (status) {
|
||||
epicsPrintf("field DTYP does not exist for recordtype %s\n",
|
||||
dbGetRecordTypeName(&dbEntry));
|
||||
status = S_dbLib_fieldNotFound;
|
||||
goto done;
|
||||
}
|
||||
|
||||
precordType = dbEntry.precordType;
|
||||
if (!precordType) {
|
||||
status = S_dbLib_badField;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ellCount(&precordType->devList) == 0) goto done;
|
||||
|
||||
ind = dbGetMenuIndex(&dbEntry);
|
||||
if (ind == -1) {
|
||||
char *pstring;
|
||||
|
||||
pstring = dbGetString(&dbEntry);
|
||||
if (strstr(pstring, "$(") || strstr(pstring, "${")) {
|
||||
link_type = MACRO_LINK;
|
||||
} else {
|
||||
status = S_dbLib_badField;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
pdevSup = (devSup *)ellNth(&precordType->devList, ind + 1);
|
||||
if (!pdevSup) {
|
||||
status = S_dbLib_badField;
|
||||
goto done;
|
||||
}
|
||||
link_type = pdevSup->link_type;
|
||||
}
|
||||
|
||||
plink = (DBLINK *)pdbentry->pfield;
|
||||
if (plink->type == link_type) goto done;
|
||||
|
||||
if (plink->text)
|
||||
{
|
||||
/* re-parse link text when DTYP has changed */
|
||||
char * link_text;
|
||||
link_text = plink->text;
|
||||
plink->text = NULL;
|
||||
dbFreeLinkContents(plink);
|
||||
plink->type = link_type;
|
||||
dbPutString(pdbentry, link_text);
|
||||
free(link_text);
|
||||
goto done;
|
||||
}
|
||||
|
||||
type = plink->type;
|
||||
if ((type == CONSTANT || type == PV_LINK ||
|
||||
type == PN_LINK || type == DB_LINK || type == CA_LINK) &&
|
||||
(link_type == CONSTANT || link_type == PV_LINK)) goto done;
|
||||
|
||||
dbFreeLinkContents(plink);
|
||||
plink->type = link_type;
|
||||
switch (plink->type) {
|
||||
case VME_IO: plink->value.vmeio.parm = pNullString; break;
|
||||
case CAMAC_IO: plink->value.camacio.parm = pNullString; break;
|
||||
case AB_IO: plink->value.abio.parm = pNullString; break;
|
||||
case GPIB_IO: plink->value.gpibio.parm = pNullString; break;
|
||||
case BITBUS_IO: plink->value.bitbusio.parm = pNullString; break;
|
||||
case INST_IO: plink->value.instio.string = pNullString; break;
|
||||
case BBGPIB_IO: plink->value.bbgpibio.parm = pNullString; break;
|
||||
case VXI_IO: plink->value.vxiio.parm = pNullString; break;
|
||||
}
|
||||
done:
|
||||
dbFinishEntry(&dbEntry);
|
||||
return(status);
|
||||
}
|
||||
|
||||
static long putParmString(char **pparm,const char *pstring)
|
||||
{
|
||||
if (*pparm && *pparm != pNullString) {
|
||||
free(*pparm);
|
||||
*pparm = pNullString;
|
||||
}
|
||||
if (!pstring) return 0;
|
||||
pstring = strchr(pstring, '@');
|
||||
if (!pstring || !*++pstring) return 0;
|
||||
*pparm = epicsStrDup(pstring);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dbFreeLinkContents(struct link *plink)
|
||||
{
|
||||
char *parm = NULL;
|
||||
@@ -309,35 +211,6 @@ static char *getpMessage(DBENTRY *pdbentry)
|
||||
return msg;
|
||||
}
|
||||
|
||||
static long putPvLink(DBENTRY *pdbentry,short pvlMask,const char *pvname)
|
||||
{
|
||||
dbFldDes *pflddes;
|
||||
DBLINK *plink;
|
||||
char *pname;
|
||||
|
||||
dbGetFieldAddress(pdbentry);
|
||||
pflddes = pdbentry->pflddes;
|
||||
if(!pflddes) return(-1);
|
||||
plink = (DBLINK *)pdbentry->pfield;
|
||||
if(!plink) return(-1);
|
||||
switch (pflddes->field_type) {
|
||||
case DBF_INLINK:
|
||||
case DBF_OUTLINK:
|
||||
case DBF_FWDLINK:
|
||||
if(plink->type != PV_LINK) return(S_dbLib_badLink);
|
||||
pname = plink->value.pv_link.pvname;
|
||||
if(pname) free((void *)pname);
|
||||
pname = dbCalloc(strlen(pvname)+1,sizeof(char));
|
||||
plink->value.pv_link.pvname = pname;
|
||||
strcpy(pname,pvname);
|
||||
plink->value.pv_link.pvlMask = pvlMask;
|
||||
return(0);
|
||||
default:
|
||||
errPrintf(-1,__FILE__, __LINE__,"Logic Error\n");
|
||||
}
|
||||
return(S_dbLib_badLink);
|
||||
}
|
||||
|
||||
/*Public only for dbStaticNoRun*/
|
||||
dbDeviceMenu *dbGetDeviceMenu(DBENTRY *pdbentry)
|
||||
{
|
||||
@@ -2017,13 +1890,348 @@ char * dbGetString(DBENTRY *pdbentry)
|
||||
return (message);
|
||||
}
|
||||
|
||||
static void cvtDecimalOrHexToShort(char *from,short *value)
|
||||
long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
|
||||
{
|
||||
if(strspn(from,"0x")==2 || strspn(from,"0X")==2) {
|
||||
sscanf(from,"%hi",value);
|
||||
} else {
|
||||
sscanf(from,"%hd",value);
|
||||
short i;
|
||||
|
||||
for (i=0; i<rtyp->no_links; i++) {
|
||||
dbLinkInfo link_info;
|
||||
dbFldDes *pflddes = rtyp->papFldDes[rtyp->link_ind[i]];
|
||||
DBLINK *plink = (DBLINK *)(((char *)prec) + pflddes->offset);
|
||||
devSup *devsup = NULL;
|
||||
|
||||
/* link fields are zero'd on allocation.
|
||||
* so are effectively CONSTANT, but with constantStr==NULL.
|
||||
* Here we initialize them to have the correct link type,
|
||||
* with zero values and empty (but non-NULL) strings.
|
||||
*/
|
||||
|
||||
if(pflddes->isDevLink) {
|
||||
devsup = (devSup *)ellNth(&rtyp->devList, prec->dtyp+1);
|
||||
}
|
||||
if(devsup)
|
||||
plink->type = devsup->link_type;
|
||||
else
|
||||
plink->type = CONSTANT;
|
||||
|
||||
switch (plink->type) {
|
||||
case CONSTANT: plink->value.constantStr = callocMustSucceed(1, 1, "init CONSTANT link"); break;
|
||||
case PV_LINK: plink->value.pv_link.pvname = callocMustSucceed(1, 1, "init PV_LINK"); break;
|
||||
case VME_IO: plink->value.vmeio.parm = pNullString; break;
|
||||
case CAMAC_IO: plink->value.camacio.parm = pNullString; break;
|
||||
case AB_IO: plink->value.abio.parm = pNullString; break;
|
||||
case GPIB_IO: plink->value.gpibio.parm = pNullString; break;
|
||||
case BITBUS_IO: plink->value.bitbusio.parm = pNullString; break;
|
||||
case INST_IO: plink->value.instio.string = pNullString; break;
|
||||
case BBGPIB_IO: plink->value.bbgpibio.parm = pNullString; break;
|
||||
case VXI_IO: plink->value.vxiio.parm = pNullString; break;
|
||||
}
|
||||
|
||||
if(!plink->text)
|
||||
continue;
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
} else if(dbCanSetLink(plink, &link_info, devsup)!=0) {
|
||||
errlogPrintf("Error: %s.%s: can't initialize link type %d with \"%s\" (type %d)\n",
|
||||
prec->name, pflddes->name, plink->type, plink->text, link_info.ltype);
|
||||
|
||||
} else if(dbSetLink(plink, &link_info, devsup)) {
|
||||
errlogPrintf("Error: %s.%s: failed to initialize link type %d with \"%s\" (type %d)\n",
|
||||
prec->name, pflddes->name, plink->type, plink->text, link_info.ltype);
|
||||
}
|
||||
free(plink->text);
|
||||
plink->text = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
|
||||
{
|
||||
char *pstr;
|
||||
size_t len;
|
||||
double value;
|
||||
|
||||
memset(pinfo, 0, sizeof(*pinfo));
|
||||
|
||||
/* Strip leading white space */
|
||||
while (*str && isspace((int)*str)) str++;
|
||||
|
||||
len = strlen(str);
|
||||
/* Strip trailing white space */
|
||||
while (len > 0 && isspace((int)str[len-1])) len--;
|
||||
|
||||
pstr = malloc(len + 1);
|
||||
if (!pstr)
|
||||
return S_dbLib_outMem;
|
||||
pinfo->target = pstr;
|
||||
|
||||
/* Check for Instrument I/O links */
|
||||
if (*str == '@') {
|
||||
pinfo->ltype = INST_IO;
|
||||
|
||||
/* Store everything after the '@' */
|
||||
memcpy(pstr, str+1, --len);
|
||||
pstr[len] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Store the stripped string */
|
||||
memcpy(pstr, str, len);
|
||||
pstr[len] = '\0';
|
||||
|
||||
/* Check for other HW link types */
|
||||
if (*pstr == '#') {
|
||||
int ret;
|
||||
char junk = 0;
|
||||
char *parm = strchr(pstr, '@'); /* find start of parm string */
|
||||
|
||||
if (parm) {
|
||||
*parm++ = '\0'; /* isolate the parm string for later */
|
||||
len -= (parm - pstr);
|
||||
}
|
||||
|
||||
/* generalized extraction of ID charactor and integer pairs (eg. "#C15 S14") */
|
||||
ret = sscanf(pinfo->target, "# %c%d %c%d %c%d %c%d %c%d %c",
|
||||
&pinfo->hwid[0], &pinfo->hwnums[0],
|
||||
&pinfo->hwid[1], &pinfo->hwnums[1],
|
||||
&pinfo->hwid[2], &pinfo->hwnums[2],
|
||||
&pinfo->hwid[3], &pinfo->hwnums[3],
|
||||
&pinfo->hwid[4], &pinfo->hwnums[4],
|
||||
&junk);
|
||||
|
||||
/* ret<0 when pattern not matched
|
||||
* ret==11 when extra non-space before '@'.
|
||||
* ret is odd when a number is missing
|
||||
*/
|
||||
if (ret<0 || ret>10 || ret%2==1) goto fail;
|
||||
|
||||
if (strcmp(pinfo->hwid, "CS")==0) pinfo->ltype = VME_IO;
|
||||
else if (strcmp(pinfo->hwid, "BCN")==0) pinfo->ltype = CAMAC_IO;
|
||||
else if (strcmp(pinfo->hwid, "BCNA")==0) pinfo->ltype = CAMAC_IO;
|
||||
else if (strcmp(pinfo->hwid, "BCNF")==0) pinfo->ltype = CAMAC_IO;
|
||||
else if (strcmp(pinfo->hwid, "BCNAF")==0) pinfo->ltype = CAMAC_IO;
|
||||
else if (strcmp(pinfo->hwid, "RMDE")==0) pinfo->ltype = RF_IO;
|
||||
else if (strcmp(pinfo->hwid, "LACS")==0) pinfo->ltype = AB_IO;
|
||||
else if (strcmp(pinfo->hwid, "LA")==0) pinfo->ltype = GPIB_IO;
|
||||
else if (strcmp(pinfo->hwid, "LNPS")==0) pinfo->ltype = BITBUS_IO;
|
||||
else if (strcmp(pinfo->hwid, "LBG")==0) pinfo->ltype = BBGPIB_IO;
|
||||
else if (strcmp(pinfo->hwid, "VCS")==0) pinfo->ltype = VXI_IO;
|
||||
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);
|
||||
} else if (!parm && pinfo->ltype == RF_IO) {
|
||||
/* RF_IO, the string isn't needed at all */
|
||||
free(pinfo->target);
|
||||
pinfo->target = NULL;
|
||||
} else {
|
||||
/* missing parm when required, or found parm when not expected */
|
||||
free(pinfo->target);
|
||||
pinfo->target = NULL;
|
||||
return S_dbLib_badField;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Link is a constant if empty or it holds just a number */
|
||||
if (len == 0 || epicsParseDouble(pstr, &value, NULL) == 0) {
|
||||
pinfo->ltype = CONSTANT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pinfo->ltype = PV_LINK;
|
||||
pstr = strchr(pstr, ' '); /* find start of link modifiers (can't be seperated by tabs) */
|
||||
if (pstr) {
|
||||
*pstr++ = '\0'; /* isolate modifiers. pinfo->target is PV name only for re-use in struct pv_link */
|
||||
|
||||
/* Space seperation of modifiers isn't required, and other chars are ignored.
|
||||
* Order of comparisons resolves ambiguity by checking for
|
||||
* longer matches first.
|
||||
* eg. "QQCPPXMSITT" is pvlOptCPP|pvlOptMSI
|
||||
*/
|
||||
|
||||
if (strstr(pstr, "NPP")) pinfo->modifiers = 0;
|
||||
else if (strstr(pstr, "CPP")) pinfo->modifiers = pvlOptCPP;
|
||||
else if (strstr(pstr, "PP")) pinfo->modifiers = pvlOptPP;
|
||||
else if (strstr(pstr, "CA")) pinfo->modifiers = pvlOptCA;
|
||||
else if (strstr(pstr, "CP")) pinfo->modifiers = pvlOptCP;
|
||||
|
||||
if (strstr(pstr, "NMS")) pinfo->modifiers |= pvlOptNMS;
|
||||
else if (strstr(pstr, "MSI")) pinfo->modifiers |= pvlOptMSI;
|
||||
else if (strstr(pstr, "MSS")) pinfo->modifiers |= pvlOptMSS;
|
||||
else if (strstr(pstr, "MS")) pinfo->modifiers |= pvlOptMS;
|
||||
|
||||
/* filter modifiers based on link type */
|
||||
switch(ftype) {
|
||||
case DBF_INLINK: /* accept all */ break;
|
||||
case DBF_OUTLINK: pinfo->modifiers &= ~pvlOptCPP; break;
|
||||
case DBF_FWDLINK: pinfo->modifiers &= pvlOptCA; break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
free(pinfo->target);
|
||||
return S_dbLib_badField;
|
||||
}
|
||||
|
||||
long dbCanSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
|
||||
{
|
||||
/* consume allocated string pinfo->target on failure */
|
||||
|
||||
int link_type = CONSTANT;
|
||||
if(devsup)
|
||||
link_type = devsup->link_type;
|
||||
if(link_type==pinfo->ltype)
|
||||
return 0;
|
||||
switch(pinfo->ltype) {
|
||||
case CONSTANT:
|
||||
case PV_LINK:
|
||||
if(link_type==CONSTANT || link_type==PV_LINK)
|
||||
return 0;
|
||||
default:
|
||||
free(pinfo->target);
|
||||
pinfo->target = NULL;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void dbSetLinkConst(DBLINK *plink, dbLinkInfo *pinfo)
|
||||
{
|
||||
plink->type = CONSTANT;
|
||||
plink->value.constantStr = pinfo->target;
|
||||
|
||||
pinfo->target = NULL;
|
||||
}
|
||||
|
||||
static
|
||||
void dbSetLinkPV(DBLINK *plink, dbLinkInfo *pinfo)
|
||||
{
|
||||
plink->type = PV_LINK;
|
||||
plink->value.pv_link.pvname = pinfo->target;
|
||||
plink->value.pv_link.pvlMask = pinfo->modifiers;
|
||||
|
||||
pinfo->target = NULL;
|
||||
}
|
||||
|
||||
static
|
||||
void dbSetLinkHW(DBLINK *plink, dbLinkInfo *pinfo)
|
||||
{
|
||||
|
||||
switch(pinfo->ltype) {
|
||||
case INST_IO:
|
||||
plink->value.instio.string = pinfo->target;
|
||||
break;
|
||||
case VME_IO:
|
||||
plink->value.vmeio.card = pinfo->hwnums[0];
|
||||
plink->value.vmeio.signal = pinfo->hwnums[1];
|
||||
plink->value.vmeio.parm = pinfo->target;
|
||||
break;
|
||||
case CAMAC_IO:
|
||||
plink->value.camacio.b = pinfo->hwnums[0];
|
||||
plink->value.camacio.c = pinfo->hwnums[1];
|
||||
plink->value.camacio.n = pinfo->hwnums[2];
|
||||
plink->value.camacio.a = pinfo->hwnums[3];
|
||||
plink->value.camacio.f = pinfo->hwnums[4];
|
||||
plink->value.camacio.parm = pinfo->target;
|
||||
break;
|
||||
case RF_IO:
|
||||
plink->value.rfio.cryo = pinfo->hwnums[0];
|
||||
plink->value.rfio.micro = pinfo->hwnums[1];
|
||||
plink->value.rfio.dataset = pinfo->hwnums[2];
|
||||
plink->value.rfio.element = pinfo->hwnums[3];
|
||||
break;
|
||||
case AB_IO:
|
||||
plink->value.abio.link = pinfo->hwnums[0];
|
||||
plink->value.abio.adapter = pinfo->hwnums[1];
|
||||
plink->value.abio.card = pinfo->hwnums[2];
|
||||
plink->value.abio.signal = pinfo->hwnums[3];
|
||||
plink->value.abio.parm = pinfo->target;
|
||||
break;
|
||||
case GPIB_IO:
|
||||
plink->value.gpibio.link = pinfo->hwnums[0];
|
||||
plink->value.gpibio.addr = pinfo->hwnums[1];
|
||||
plink->value.gpibio.parm = pinfo->target;
|
||||
break;
|
||||
case BITBUS_IO:
|
||||
plink->value.bitbusio.link = pinfo->hwnums[0];
|
||||
plink->value.bitbusio.node = pinfo->hwnums[1];
|
||||
plink->value.bitbusio.port = pinfo->hwnums[2];
|
||||
plink->value.bitbusio.signal = pinfo->hwnums[3];
|
||||
plink->value.bitbusio.parm = pinfo->target;
|
||||
break;
|
||||
case BBGPIB_IO:
|
||||
plink->value.bbgpibio.link = pinfo->hwnums[0];
|
||||
plink->value.bbgpibio.bbaddr = pinfo->hwnums[1];
|
||||
plink->value.bbgpibio.gpibaddr = pinfo->hwnums[2];
|
||||
plink->value.bbgpibio.parm = pinfo->target;
|
||||
break;
|
||||
case VXI_IO:
|
||||
if(strcmp(pinfo->hwid, "VCS")==0) {
|
||||
plink->value.vxiio.flag=VXIDYNAMIC;
|
||||
plink->value.vxiio.frame = pinfo->hwnums[0];
|
||||
plink->value.vxiio.slot = pinfo->hwnums[1];
|
||||
plink->value.vxiio.signal = pinfo->hwnums[2];
|
||||
} else if(strcmp(pinfo->hwid, "VS")==0) {
|
||||
plink->value.vxiio.flag=VXISTATIC;
|
||||
plink->value.vxiio.la = pinfo->hwnums[0];
|
||||
plink->value.vxiio.signal = pinfo->hwnums[1];
|
||||
} else {
|
||||
cantProceed("dbSetLinkHW: logic error, unknown VXI_IO variant");
|
||||
}
|
||||
plink->value.vxiio.parm = pinfo->target;
|
||||
break;
|
||||
|
||||
default:
|
||||
cantProceed("dbSetLinkHW: logic error, unhandled link type");
|
||||
return;
|
||||
}
|
||||
|
||||
plink->type = pinfo->ltype;
|
||||
|
||||
pinfo->target = NULL; /* now owned by link field */
|
||||
}
|
||||
|
||||
long dbSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
|
||||
{
|
||||
int ret = 0;
|
||||
int link_type = CONSTANT;
|
||||
|
||||
if(devsup)
|
||||
link_type = devsup->link_type;
|
||||
|
||||
if(link_type==CONSTANT || link_type==PV_LINK) {
|
||||
switch(pinfo->ltype) {
|
||||
case CONSTANT:
|
||||
dbFreeLinkContents(plink);
|
||||
dbSetLinkConst(plink, pinfo); break;
|
||||
case PV_LINK:
|
||||
dbFreeLinkContents(plink);
|
||||
dbSetLinkPV(plink, pinfo); break;
|
||||
default:
|
||||
errlogMessage("Warning: dbSetLink: forgot to test with dbCanSetLink() or logic error");
|
||||
goto fail; /* can't assign HW link */
|
||||
}
|
||||
|
||||
} else if(link_type==pinfo->ltype) {
|
||||
dbFreeLinkContents(plink);
|
||||
dbSetLinkHW(plink, pinfo);
|
||||
|
||||
} else
|
||||
goto fail;
|
||||
|
||||
return ret;
|
||||
fail:
|
||||
free(pinfo->target);
|
||||
pinfo->target = NULL;
|
||||
return S_dbLib_badField;
|
||||
}
|
||||
|
||||
long dbPutString(DBENTRY *pdbentry,const char *pstring)
|
||||
@@ -2069,351 +2277,39 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
|
||||
case DBF_FLOAT:
|
||||
case DBF_DOUBLE:
|
||||
case DBF_MENU:
|
||||
case DBF_DEVICE:
|
||||
status = dbPutStringNum(pdbentry,pstring);
|
||||
break;
|
||||
|
||||
case DBF_DEVICE: {
|
||||
DBENTRY dbEntry;
|
||||
char *name;
|
||||
|
||||
status = dbPutStringNum(pdbentry, pstring);
|
||||
if (status) return status;
|
||||
|
||||
name = dbGetRelatedField(pdbentry);
|
||||
if (!name) return 0;
|
||||
|
||||
dbCopyEntryContents(pdbentry, &dbEntry);
|
||||
status = dbFindField(&dbEntry, name);
|
||||
if (!status)
|
||||
status = setLinkType(&dbEntry);
|
||||
dbFinishEntry(&dbEntry);
|
||||
return status;
|
||||
}
|
||||
|
||||
case DBF_INLINK:
|
||||
case DBF_OUTLINK:
|
||||
case DBF_FWDLINK: {
|
||||
DBLINK *plink;
|
||||
char string[80];
|
||||
char *pstr = string;
|
||||
dbLinkInfo link_info;
|
||||
DBLINK *plink = (DBLINK *)pfield;
|
||||
|
||||
if (!pfield)
|
||||
return S_dbLib_fieldNotFound;
|
||||
status = dbParseLink(pstring, pflddes->field_type, &link_info);
|
||||
|
||||
plink = (DBLINK *)pfield;
|
||||
dbFreeLinkContents(plink);
|
||||
if (stringHasMacro) {
|
||||
plink->type = MACRO_LINK;
|
||||
plink->value.macro_link.macroStr = epicsStrDup(pstring);
|
||||
goto done;
|
||||
}
|
||||
if(status==0 && plink->type==CONSTANT && plink->value.constantStr==NULL) {
|
||||
/* links not yet initialized by dbInitRecordLinks() */
|
||||
free(plink->text);
|
||||
plink->text = epicsStrDup(pstring);
|
||||
free(link_info.target);
|
||||
|
||||
if (strcmp(pflddes->name, "INP") == 0 ||
|
||||
strcmp(pflddes->name, "OUT") == 0) {
|
||||
status = setLinkType(pdbentry); /* This uses DTYP to look up and set plink->type, necessary for default DTYP */
|
||||
if (status) {
|
||||
errMessage(status,"in dbPutString from setLinkType");
|
||||
return status;
|
||||
}
|
||||
/* store link text in case DTYP changes later */
|
||||
plink->text = malloc(strlen(pstring) + 1);
|
||||
if (plink->text)
|
||||
strcpy(plink->text, pstring);
|
||||
}
|
||||
if (strlen(pstring) >= sizeof(string)) {
|
||||
status = S_dbLib_badField;
|
||||
errMessage(status,
|
||||
"dbPutString received a string that is too long");
|
||||
return status;
|
||||
}
|
||||
strcpy(pstr, pstring);
|
||||
/* Strip leading blanks and tabs */
|
||||
while (*pstr && (*pstr == ' ' || *pstr == '\t')) pstr++;
|
||||
/* Strip trailing blanks and tabs */
|
||||
if (pstr) {
|
||||
int ind;
|
||||
} else if(status==0) {
|
||||
/* assignment after init (eg. autosave restore) */
|
||||
struct dbCommon *prec = pdbentry->precnode->precord;
|
||||
devSup *devsup = (devSup *)ellNth(&pdbentry->precordType->devList, prec->dtyp+1);
|
||||
status = dbCanSetLink(plink, &link_info, devsup);
|
||||
if(status==0)
|
||||
status = dbSetLink(plink, &link_info, devsup);
|
||||
}
|
||||
|
||||
for (ind = (int) strlen(pstr) - 1; ind >= 0; ind--) {
|
||||
if (pstr[ind] != ' ' && pstr[ind] != '\t') break;
|
||||
pstr[ind] = '\0';
|
||||
}
|
||||
}
|
||||
if (!pstr || !*pstr) {
|
||||
if (plink->type == PV_LINK) dbCvtLinkToConstant(pdbentry);
|
||||
if (plink->type != CONSTANT) return S_dbLib_badField;
|
||||
free((void *)plink->value.constantStr);
|
||||
plink->value.constantStr = NULL;
|
||||
goto done;
|
||||
}
|
||||
switch (plink->type) {
|
||||
case CONSTANT:
|
||||
case PV_LINK: {
|
||||
short ppOpt = 0;
|
||||
short msOpt = 0;
|
||||
char *end;
|
||||
char *enddouble;
|
||||
char *endlong;
|
||||
|
||||
/* Check first to see if string is a constant*/
|
||||
/*It is a string if epicsStrtod or strtol eats entire string*/
|
||||
/*leading and trailing blanks have already been stripped*/
|
||||
(void) epicsStrtod(pstr, &enddouble);
|
||||
(void) strtol(pstr, &endlong, 0);
|
||||
|
||||
if (*enddouble == 0 || *endlong == 0) {
|
||||
if (plink->type == PV_LINK) dbCvtLinkToConstant(pdbentry);
|
||||
if (!plink->value.constantStr ||
|
||||
strlen(plink->value.constantStr) < strlen(pstr)) {
|
||||
free(plink->value.constantStr);
|
||||
plink->value.constantStr =
|
||||
dbCalloc(strlen(pstr) + 1, sizeof(char));
|
||||
}
|
||||
strcpy(plink->value.constantStr, pstr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (plink->type==CONSTANT) dbCvtLinkToPvlink(pdbentry);
|
||||
end = strchr(pstr,' ');
|
||||
if (end) {
|
||||
switch (pflddes->field_type) {
|
||||
case DBF_INLINK: {
|
||||
if (strstr(end, "NPP")) ppOpt = 0;
|
||||
else if (strstr(end, "CPP")) ppOpt = pvlOptCPP;
|
||||
else if (strstr(end, "PP")) ppOpt = pvlOptPP;
|
||||
else if (strstr(end, "CA")) ppOpt = pvlOptCA;
|
||||
else if (strstr(end, "CP")) ppOpt = pvlOptCP;
|
||||
else ppOpt = 0;
|
||||
if (strstr(end, "NMS")) msOpt = pvlOptNMS;
|
||||
else if (strstr(end, "MSI")) msOpt = pvlOptMSI;
|
||||
else if (strstr(end, "MSS")) msOpt = pvlOptMSS;
|
||||
/*must be the last one:*/ else if (strstr(end, "MS")) msOpt = pvlOptMS;
|
||||
else msOpt = 0;
|
||||
*end = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case DBF_OUTLINK: {
|
||||
if (strstr(end, "NPP")) ppOpt = 0;
|
||||
else if(strstr(end, "PP")) ppOpt = pvlOptPP;
|
||||
else if(strstr(end, "CA")) ppOpt = pvlOptCA;
|
||||
else ppOpt = 0;
|
||||
if (strstr(end, "NMS")) msOpt = pvlOptNMS;
|
||||
else if(strstr(end, "MSI")) msOpt = pvlOptMSI;
|
||||
else if(strstr(end, "MSS")) msOpt = pvlOptMSS;
|
||||
/*must be the last one:*/ else if(strstr(end, "MS")) msOpt = pvlOptMS;
|
||||
else msOpt = 0;
|
||||
*end = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case DBF_FWDLINK: {
|
||||
if (strstr(end, "NPP")) ppOpt = 0;
|
||||
else if (strstr(end, "CA")) ppOpt = pvlOptCA;
|
||||
else ppOpt = 0;
|
||||
msOpt = 0;
|
||||
*end = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
epicsPrintf("dbPutString: Logic Error\n");
|
||||
}
|
||||
}
|
||||
status = putPvLink(pdbentry,ppOpt|msOpt,pstr);
|
||||
goto done;
|
||||
}
|
||||
/*break; is unnecessary*/
|
||||
case VME_IO: {
|
||||
char *end;
|
||||
|
||||
if (!(end = strchr(pstr,'#'))) return S_dbLib_badField;
|
||||
pstr = end + 1;
|
||||
if (!(end = strchr(pstr,'C'))) return S_dbLib_badField;
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.vmeio.card);
|
||||
if (!(end = strchr(pstr,'S'))) return S_dbLib_badField;
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr, &plink->value.vmeio.signal);
|
||||
status = putParmString(&plink->value.vmeio.parm, pstr);
|
||||
}
|
||||
break;
|
||||
|
||||
case CAMAC_IO: {
|
||||
char *end;
|
||||
|
||||
if (!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
if (!(end = strchr(pstr,'B'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.b);
|
||||
if (!(end = strchr(pstr,'C'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.c);
|
||||
if (!(end = strchr(pstr,'N'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.n);
|
||||
if (!(end = strchr(pstr,'A'))) {
|
||||
plink->value.camacio.a = 0;
|
||||
} else {
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.a);
|
||||
}
|
||||
if (!(end = strchr(pstr,'F'))) {
|
||||
plink->value.camacio.f = 0;
|
||||
} else {
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.f);
|
||||
}
|
||||
status = putParmString(&plink->value.camacio.parm,pstr);
|
||||
}
|
||||
break;
|
||||
|
||||
case RF_IO: {
|
||||
char *end;
|
||||
|
||||
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
if(!(end = strchr(pstr,'R'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.rfio.cryo);
|
||||
if(!(end = strchr(pstr,'M'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.rfio.micro);
|
||||
if(!(end = strchr(pstr,'D'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.rfio.dataset);
|
||||
if(!(end = strchr(pstr,'E'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.rfio.element);
|
||||
}
|
||||
break;
|
||||
case AB_IO: {
|
||||
char *end;
|
||||
|
||||
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
if(!(end = strchr(pstr,'L'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.abio.link);
|
||||
if(!(end = strchr(pstr,'A'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.abio.adapter);
|
||||
if(!(end = strchr(pstr,'C'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.abio.card);
|
||||
if(!(end = strchr(pstr,'S'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.abio.signal);
|
||||
status = putParmString(&plink->value.abio.parm,pstr);
|
||||
}
|
||||
break;
|
||||
case GPIB_IO: {
|
||||
char *end;
|
||||
|
||||
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
if(!(end = strchr(pstr,'L'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.gpibio.link);
|
||||
if(!(end = strchr(pstr,'A'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.gpibio.addr);
|
||||
status = putParmString(&plink->value.gpibio.parm,pstr);
|
||||
}
|
||||
break;
|
||||
case BITBUS_IO: {
|
||||
/* jbk - the bbgpib struct uses unsigned char's instead
|
||||
of short, so read values into short and then convert */
|
||||
|
||||
char *end;
|
||||
short tmp_val;
|
||||
|
||||
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
if(!(end = strchr(pstr,'L'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&tmp_val);
|
||||
plink->value.bitbusio.link=(unsigned char)tmp_val;
|
||||
if(!(end = strchr(pstr,'N'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&tmp_val);
|
||||
plink->value.bitbusio.node=(unsigned char)tmp_val;
|
||||
if(!(end = strchr(pstr,'P'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&tmp_val);
|
||||
plink->value.bitbusio.port=(unsigned char)tmp_val;
|
||||
if(!(end = strchr(pstr,'S'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&tmp_val);
|
||||
plink->value.bitbusio.signal=(unsigned char)tmp_val;
|
||||
status = putParmString(&plink->value.bitbusio.parm,pstr);
|
||||
}
|
||||
break;
|
||||
case BBGPIB_IO: {
|
||||
/* jbk - the bbgpib struct uses unsigned char's instead
|
||||
of short, so read values into short and then convert */
|
||||
|
||||
char *end;
|
||||
short tmp_val;
|
||||
|
||||
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
if(!(end = strchr(pstr,'L'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&tmp_val);
|
||||
plink->value.bbgpibio.link=(unsigned char)tmp_val;
|
||||
if(!(end = strchr(pstr,'B'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&tmp_val);
|
||||
plink->value.bbgpibio.bbaddr=(unsigned char)tmp_val;
|
||||
if(!(end = strchr(pstr,'G'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&tmp_val);
|
||||
plink->value.bbgpibio.gpibaddr=(unsigned char)tmp_val;
|
||||
status = putParmString(&plink->value.bbgpibio.parm,pstr);
|
||||
}
|
||||
break;
|
||||
case VXI_IO: {
|
||||
char *end;
|
||||
|
||||
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
memset((char *)&plink->value.vxiio,0,sizeof(struct vxiio));
|
||||
plink->value.vxiio.parm = pNullString;
|
||||
if(!((end = strchr(pstr,'C'))&&(end < strchr(pstr,'@')) )) {
|
||||
plink->value.vxiio.flag = VXISTATIC;
|
||||
if(!(end = strchr(pstr,'V'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.vxiio.la);
|
||||
} else {
|
||||
plink->value.vxiio.flag = VXIDYNAMIC;
|
||||
if(!(end = strchr(pstr,'V'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.vxiio.frame);
|
||||
if(!(end = strchr(pstr,'C'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.vxiio.slot);
|
||||
}
|
||||
if((end = strchr(pstr,'S'))) {
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.vxiio.signal);
|
||||
} else {
|
||||
plink->value.vxiio.signal = 0;
|
||||
}
|
||||
status = putParmString(&plink->value.vxiio.parm,pstr);
|
||||
}
|
||||
break;
|
||||
case INST_IO: {
|
||||
status = putParmString(&plink->value.instio.string, pstr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return S_dbLib_badField;
|
||||
}
|
||||
done:
|
||||
|
||||
if (!status && strcmp(pflddes->name, "VAL") == 0) {
|
||||
DBENTRY dbentry;
|
||||
|
||||
|
||||
@@ -36,6 +36,39 @@ char *dbRecordName(DBENTRY *pdbentry);
|
||||
char *dbGetStringNum(DBENTRY *pdbentry);
|
||||
long dbPutStringNum(DBENTRY *pdbentry,const char *pstring);
|
||||
|
||||
typedef struct dbLinkInfo {
|
||||
short ltype;
|
||||
|
||||
/* full link string for CONSTANT and PV_LINK,
|
||||
* parm string for HW links*/
|
||||
char *target;
|
||||
|
||||
/* for PV_LINK */
|
||||
short modifiers;
|
||||
|
||||
/* HW links */
|
||||
char hwid[6]; /* one extra element for a nil */
|
||||
int hwnums[5];
|
||||
} dbLinkInfo;
|
||||
|
||||
long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec);
|
||||
|
||||
/* Parse link string. no record locks needed.
|
||||
* on success caller must free pinfo->target
|
||||
*/
|
||||
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.
|
||||
* Frees pinfo->target on failure.
|
||||
*/
|
||||
long dbCanSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup);
|
||||
/* Set link field. source record must be locked (target record too
|
||||
* when a DB_LINK is created)
|
||||
* Unconditionally takes ownership of pinfo->target
|
||||
*/
|
||||
long dbSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *dset);
|
||||
|
||||
/* The following is for path */
|
||||
typedef struct dbPathNode {
|
||||
ELLNODE node;
|
||||
|
||||
+15
-9
@@ -86,7 +86,14 @@ static void initDatabase(void);
|
||||
static void initialProcess(void);
|
||||
static void exitDatabase(void *dummy);
|
||||
|
||||
|
||||
/*
|
||||
* Iterate through all record instances (but not aliases),
|
||||
* calling a function for each one.
|
||||
*/
|
||||
typedef void (*recIterFunc)(dbRecordType *rtyp, dbCommon *prec, void *user);
|
||||
|
||||
static void iterateRecords(recIterFunc func, void *user);
|
||||
|
||||
/*
|
||||
* Initialize EPICS on the IOC.
|
||||
*/
|
||||
@@ -126,8 +133,14 @@ static int iocBuild_1(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void prepareLinks(dbRecordType *rtyp, dbCommon *prec, void *junk)
|
||||
{
|
||||
dbInitRecordLinks(rtyp, prec);
|
||||
}
|
||||
|
||||
static int iocBuild_2(void)
|
||||
{
|
||||
iterateRecords(prepareLinks, NULL);
|
||||
initHookAnnounce(initHookAfterCaLinkInit);
|
||||
|
||||
initDrvSup();
|
||||
@@ -419,12 +432,6 @@ static void finishDevSup(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate through all record instances (but not aliases),
|
||||
* calling a function for each one.
|
||||
*/
|
||||
typedef void (*recIterFunc)(dbRecordType *rtyp, dbCommon *prec, void *user);
|
||||
|
||||
static void iterateRecords(recIterFunc func, void *user)
|
||||
{
|
||||
@@ -490,8 +497,7 @@ static void doResolveLinks(dbRecordType *pdbRecordType, dbCommon *precord,
|
||||
dbFldDes *pdbFldDes = papFldDes[link_ind[j]];
|
||||
DBLINK *plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
|
||||
|
||||
if (ellCount(&precord->rdes->devList) > 0 &&
|
||||
(strcmp(pdbFldDes->name, "INP") == 0 || strcmp(pdbFldDes->name, "OUT") == 0)) {
|
||||
if (ellCount(&precord->rdes->devList) > 0 && pdbFldDes->isDevLink) {
|
||||
devSup *pdevSup = dbDTYPtoDevSup(pdbRecordType, precord->dtyp);
|
||||
|
||||
if (pdevSup) {
|
||||
|
||||
Reference in New Issue
Block a user