From 13294f80cc171cb5d1db1f8a653e18f0c68e7b6d Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 27 Apr 2016 20:47:17 -0500 Subject: [PATCH] Add basic support and tests for a JSON link address type --- src/ioc/db/test/dbLinkdset.c | 1 + src/ioc/db/test/dbLinkdset.dbd | 1 + src/ioc/db/test/dbPutLinkTest.c | 16 +++++++-- src/ioc/db/test/dbPutLinkTest.db | 4 +++ src/ioc/dbStatic/dbStaticLib.c | 61 ++++++++++++++++++++++++-------- src/ioc/dbStatic/link.h | 10 ++++-- src/tools/DBD/Device.pm | 1 + 7 files changed, 75 insertions(+), 19 deletions(-) diff --git a/src/ioc/db/test/dbLinkdset.c b/src/ioc/db/test/dbLinkdset.c index 6e775df7b..c10cdd3bf 100644 --- a/src/ioc/db/test/dbLinkdset.c +++ b/src/ioc/db/test/dbLinkdset.c @@ -29,6 +29,7 @@ long link_test_noop(void *junk) static dset devxLTest ## LTYPE = {4, NULL, &link_test_init, &link_test_noop, &link_test_noop}; \ epicsExportAddress(dset, devxLTest ## LTYPE); +DEFDSET(JSON_STR) DEFDSET(VME_IO) DEFDSET(CAMAC_IO) DEFDSET(AB_IO) diff --git a/src/ioc/db/test/dbLinkdset.dbd b/src/ioc/db/test/dbLinkdset.dbd index 84d5eefe9..14ecaaadf 100644 --- a/src/ioc/db/test/dbLinkdset.dbd +++ b/src/ioc/db/test/dbLinkdset.dbd @@ -1,3 +1,4 @@ +device(x, JSON_STR, devxLTestJSON_STR, "Unit Test JSON_STR") device(x, VME_IO, devxLTestVME_IO, "Unit Test VME_IO") device(x, CAMAC_IO, devxLTestCAMAC_IO, "Unit Test CAMAC_IO") device(x, AB_IO, devxLTestAB_IO, "Unit Test AB_IO") diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c index 5fcab16b8..1423b6fe4 100644 --- a/src/ioc/db/test/dbPutLinkTest.c +++ b/src/ioc/db/test/dbPutLinkTest.c @@ -60,6 +60,7 @@ static const struct testParseDataT { {"#B11 C12 N13 A14 F15 @cparam", {CAMAC_IO, "cparam", 0, "BCNAF", {11, 12, 13, 14, 15}}}, {" #B111 C112 N113 @cparam", {CAMAC_IO, "cparam", 0, "BCN", {111, 112, 113}}}, {" @hello world ", {INST_IO, "hello world", 0, "", /*{}*/}}, + {" {\"x\":{}} ", {JSON_STR, "{\"x\":{}}", 0, "", /*{}*/}}, {NULL} }; @@ -239,6 +240,7 @@ typedef struct { } testHWDataT; static const testHWDataT testHWData[] = { + {"rJSON_STR", JSON_STR, "{\"JSON\":{}}", {0}, "{\"JSON\":{}}"}, {"rVME_IO", VME_IO, "#C100 S101 @parm VME_IO", {100, 101}, "parm VME_IO"}, {"rCAMAC_IO", CAMAC_IO, "#B11 C12 N13 A14 F15 @parm CAMAC_IO", {11, 12, 13, 14, 15}, "parm CAMAC_IO"}, {"rAB_IO", AB_IO, "#L21 A22 C23 S24 @parm AB_IO", {21, 22, 23, 24}, "parm AB_IO"}, @@ -255,6 +257,9 @@ static const testHWDataT testHWData[] = { static void testLink(DBLINK *plink, const testHWDataT *td) { switch(td->ltype) { + case JSON_STR: + testOk1(strcmp(plink->value.json.string, td->parm)==0); + break; case VME_IO: testOk1(plink->value.vmeio.card==td->vals[0]); testOk1(plink->value.vmeio.signal==td->vals[1]); @@ -360,6 +365,7 @@ static void testHWInitSet(void) } static const testHWDataT testHWData2[] = { + {"rJSON_STR", JSON_STR, "{\"json\":{}}", {0}, "{\"json\":{}}"}, {"rVME_IO", VME_IO, "#C200 S201 @another VME_IO", {200, 201}, "another VME_IO"}, {"rCAMAC_IO", CAMAC_IO, "#B111 C112 N113 A114 F115 @CAMAC_IO", {111, 112, 113, 114, 115}, "CAMAC_IO"}, {"rAB_IO", AB_IO, "#L121 A122 C123 S124 @another AB_IO", {121, 122, 123, 124}, "another AB_IO"}, @@ -482,9 +488,15 @@ static void testLinkFail(void) /* INST_IO doesn't accept empty string */ testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, ""); - /* INST_IO doesn't accept empty string */ + /* INST_IO doesn't accept string without @ */ testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, "abc"); + /* JSON_STR doesn't accept empty string */ + testdbPutFieldFail(S_dbLib_badField, "rJSON_STR.INP", DBR_STRING, ""); + + /* JSON_STR doesn't accept string without braces */ + testdbPutFieldFail(S_dbLib_badField, "rJSON_STR.INP", DBR_STRING, "abc"); + /* syntax errors */ testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "#S201 C200 @another VME_IO"); testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "C200 #S201"); @@ -504,7 +516,7 @@ static void testLinkFail(void) MAIN(dbPutLinkTest) { - testPlan(251); + testPlan(263); testLinkParse(); testLinkFailParse(); testCADBSet(); diff --git a/src/ioc/db/test/dbPutLinkTest.db b/src/ioc/db/test/dbPutLinkTest.db index 7753b5b08..421d98f52 100644 --- a/src/ioc/db/test/dbPutLinkTest.db +++ b/src/ioc/db/test/dbPutLinkTest.db @@ -3,6 +3,10 @@ record(x, "x2") {} record(x, "x3") {} record(x, "x4") {} +record(x, "rJSON_STR") { + field(DTYP, "Unit Test JSON_STR") + field(INP, "{\"JSON\":{}}") +} record(x, "rVME_IO") { field(DTYP, "Unit Test VME_IO") field(INP, "#C100 S101 @parm VME_IO") diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index e0b514c81..6039266ed 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -67,6 +67,7 @@ epicsShareDef maplinkType pamaplinkType[LINK_NTYPES] = { {"GPIB_IO",GPIB_IO}, {"BITBUS_IO",BITBUS_IO}, {"MACRO_LINK",MACRO_LINK}, + {"JSON_STR",JSON_STR}, {"PN_LINK",PN_LINK}, {"DB_LINK",DB_LINK}, {"CA_LINK",CA_LINK}, @@ -121,6 +122,7 @@ void dbFreeLinkContents(struct link *plink) case CONSTANT: free((void *)plink->value.constantStr); break; case MACRO_LINK: free((void *)plink->value.macro_link.macroStr); break; case PV_LINK: free((void *)plink->value.pv_link.pvname); break; + case JSON_STR: parm = plink->value.json.string; break; case VME_IO: parm = plink->value.vmeio.parm; break; case CAMAC_IO: parm = plink->value.camacio.parm; break; case AB_IO: parm = plink->value.abio.parm; break; @@ -1918,6 +1920,9 @@ char * dbGetString(DBENTRY *pdbentry) dbMsgCpy(pdbentry, ""); } break; + case JSON_STR: + dbMsgCpy(pdbentry, plink->value.json.string); + break; case PN_LINK: dbMsgPrint(pdbentry, "%s%s", plink->value.pv_link.pvname ? plink->value.pv_link.pvname : "", @@ -2169,6 +2174,7 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec) */ case CONSTANT: plink->value.constantStr = NULL; break; case PV_LINK: plink->value.pv_link.pvname = callocMustSucceed(1, 1, "init PV_LINK"); break; + case JSON_STR: plink->value.json.string = pNullString; 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; @@ -2235,6 +2241,12 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo) memcpy(pstr, str, len); pstr[len] = '\0'; + /* Check for braces => JSON */ + if (*str == '{' && str[len-1] == '}') { + pinfo->ltype = JSON_STR; + return 0; + } + /* Check for other HW link types */ if (*pstr == '#') { int ret; @@ -2336,16 +2348,18 @@ fail: long dbCanSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup) { /* consume allocated string pinfo->target on failure */ - int link_type = CONSTANT; - if(devsup) + + if (devsup) link_type = devsup->link_type; - if(link_type==pinfo->ltype) + if (link_type == pinfo->ltype) return 0; - switch(pinfo->ltype) { + + switch (pinfo->ltype) { case CONSTANT: + case JSON_STR: case PV_LINK: - if(link_type==CONSTANT || link_type==PV_LINK) + if (link_type == CONSTANT || link_type == PV_LINK) return 0; default: free(pinfo->target); @@ -2373,11 +2387,22 @@ void dbSetLinkPV(DBLINK *plink, dbLinkInfo *pinfo) pinfo->target = NULL; } +static +void dbSetLinkJSON(DBLINK *plink, dbLinkInfo *pinfo) +{ + plink->type = JSON_STR; + plink->value.json.string = pinfo->target; + + pinfo->target = NULL; +} + static void dbSetLinkHW(DBLINK *plink, dbLinkInfo *pinfo) { - switch(pinfo->ltype) { + case JSON_STR: + plink->value.json.string = pinfo->target; + break; case INST_IO: plink->value.instio.string = pinfo->target; break; @@ -2456,27 +2481,33 @@ long dbSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup) int ret = 0; int link_type = CONSTANT; - if(devsup) + if (devsup) link_type = devsup->link_type; - if(link_type==CONSTANT || link_type==PV_LINK) { - switch(pinfo->ltype) { + if (link_type == CONSTANT || link_type == PV_LINK) { + switch (pinfo->ltype) { case CONSTANT: dbFreeLinkContents(plink); - dbSetLinkConst(plink, pinfo); break; + dbSetLinkConst(plink, pinfo); + break; case PV_LINK: dbFreeLinkContents(plink); - dbSetLinkPV(plink, pinfo); break; + dbSetLinkPV(plink, pinfo); + break; + case JSON_STR: + dbFreeLinkContents(plink); + dbSetLinkJSON(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) { + } + else if (link_type == pinfo->ltype) { dbFreeLinkContents(plink); dbSetLinkHW(plink, pinfo); - - } else + } + else goto fail; return ret; diff --git a/src/ioc/dbStatic/link.h b/src/ioc/dbStatic/link.h index e0063a68b..19ab68081 100644 --- a/src/ioc/dbStatic/link.h +++ b/src/ioc/dbStatic/link.h @@ -33,7 +33,7 @@ extern "C" { #define GPIB_IO 5 #define BITBUS_IO 6 #define MACRO_LINK 7 - +#define JSON_STR 8 #define PN_LINK 9 #define DB_LINK 10 #define CA_LINK 11 @@ -41,7 +41,7 @@ extern "C" { #define BBGPIB_IO 13 /* bitbus -> gpib */ #define RF_IO 14 #define VXI_IO 15 -#define LINK_NTYPES 15 +#define LINK_NTYPES 16 typedef struct maplinkType { char *strvalue; int value; @@ -87,6 +87,11 @@ struct pv_link { short lastGetdbrType; /* last dbrType for DB or CA get */ }; +struct json_link { + char *string; + /* ... */ +}; + /* structure of a VME io channel */ struct vmeio { short card; @@ -167,6 +172,7 @@ struct vxiio { union value { char *constantStr; /*constant string*/ struct macro_link macro_link; /* link containing macro substitution*/ + struct json_link json; /* JSON-encoded link */ struct pv_link pv_link; /* link to process variable*/ struct vmeio vmeio; /* vme io point */ struct camacio camacio; /* camac io point */ diff --git a/src/tools/DBD/Device.pm b/src/tools/DBD/Device.pm index 5d13a9655..62ee45e28 100644 --- a/src/tools/DBD/Device.pm +++ b/src/tools/DBD/Device.pm @@ -5,6 +5,7 @@ use DBD::Base; my %link_types = ( CONSTANT => qr/$RXnum/o, PV_LINK => qr/$RXname \s+ [.NPCAMS ]*/ox, + JSON_STR => qr/\{ .* \}/ox, VME_IO => qr/\# (?: \s* [CS] \s* $RXintx)* \s* (?: @ .*)?/ox, CAMAC_IO => qr/\# (?: \s* [BCNAF] \s* $RXintx)* \s* (?: @ .*)?/ox, RF_IO => qr/\# (?: \s* [RMDE] \s* $RXintx)*/ox,