diff --git a/src/ioc/db/Makefile b/src/ioc/db/Makefile index 3f08bbe83..0c874ccff 100644 --- a/src/ioc/db/Makefile +++ b/src/ioc/db/Makefile @@ -21,6 +21,7 @@ INC += dbChannel.h INC += dbConstLink.h INC += dbConvert.h INC += dbConvertFast.h +INC += dbConvertJSON.h INC += dbDbLink.h INC += dbExtractArray.h INC += dbEvent.h @@ -68,6 +69,7 @@ dbCore_SRCS += dbBkpt.c dbCore_SRCS += dbChannel.c dbCore_SRCS += dbConstLink.c dbCore_SRCS += dbConvert.c +dbCore_SRCS += dbConvertJSON.c dbCore_SRCS += dbDbLink.c dbCore_SRCS += dbFastLinkConv.c dbCore_SRCS += dbExtractArray.c diff --git a/src/ioc/db/dbCa.c b/src/ioc/db/dbCa.c index de37682b6..5f532ad5d 100644 --- a/src/ioc/db/dbCa.c +++ b/src/ioc/db/dbCa.c @@ -709,8 +709,8 @@ static void scanLinkOnce(dbCommon *prec, caLink *pca) { } static lset dbCa_lset = { - NULL, dbCaRemoveLink, + NULL, NULL, isConnected, getDBFtype, getElements, dbCaGetLink, diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c index 022ba7fe9..1c1f89c3a 100644 --- a/src/ioc/db/dbConstLink.c +++ b/src/ioc/db/dbConstLink.c @@ -12,24 +12,19 @@ * Current Author: Andrew Johnson */ -#include #include -#include "cvtFast.h" #include "dbDefs.h" -#include "errlog.h" #define epicsExportSharedSymbols #include "dbAccessDefs.h" #include "dbAddr.h" -#include "dbBase.h" #include "dbCommon.h" #include "dbConvertFast.h" -#include "dbConvert.h" +#include "dbConvertJSON.h" #include "dbFldTypes.h" #include "dbLink.h" #include "link.h" -#include "recGbl.h" /***************************** Constant Links *****************************/ @@ -46,14 +41,14 @@ void dbConstAddLink(struct link *plink) plink->lset = &dbConst_lset; } -static long dbConstLoadLink(struct link *plink, short dbrType, void *pbuffer) +/**************************** Member functions ****************************/ + +static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer) { if (!plink->value.constantStr) return S_db_badField; - plink->lset = &dbConst_lset; - - /* Constant strings are always numeric */ + /* Constant scalars are always numeric */ if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE) dbrType = DBF_USHORT; @@ -61,6 +56,19 @@ static long dbConstLoadLink(struct link *plink, short dbrType, void *pbuffer) (plink->value.constantStr, pbuffer, NULL); } +static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer, + long *pnReq) +{ + if (!plink->value.constantStr) + return S_db_badField; + + /* No support for arrays of choice types */ + if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE) + return S_db_badField; + + return dbPutConvertJSON(plink->value.constantStr, dbrType, pbuffer, pnReq); +} + static long dbConstGetNelements(const struct link *plink, long *nelements) { *nelements = 0; @@ -76,8 +84,9 @@ static long dbConstGetValue(struct link *plink, short dbrType, void *pbuffer, } static lset dbConst_lset = { - dbConstLoadLink, NULL, + dbConstLoadScalar, + dbConstLoadArray, NULL, NULL, dbConstGetNelements, dbConstGetValue, diff --git a/src/ioc/db/dbConvertJSON.c b/src/ioc/db/dbConvertJSON.c new file mode 100644 index 000000000..d877fe043 --- /dev/null +++ b/src/ioc/db/dbConvertJSON.c @@ -0,0 +1,164 @@ +/*************************************************************************\ +* 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. +\*************************************************************************/ +/* dbConvertJSON.c */ + +#include +#include + +#include "dbDefs.h" +#include "yajl_alloc.h" +#include "yajl_parse.h" + +#define epicsExportSharedSybols +#include "dbAccessDefs.h" +#include "dbConvertFast.h" + +typedef long (*FASTCONVERT)(); + +typedef struct parseContext { + int depth; + short dbrType; + short dbrSize; + void *pdest; + int elems; +} parseContext; + +static int dbcj_null(void *ctx) { + return 0; /* Illegal */ +} + +static int dbcj_boolean(void *ctx, int val) { + return 0; /* Illegal */ +} + +static int dbcj_integer(void *ctx, long num) { + parseContext *parser = (parseContext *) ctx; + epicsInt32 val32 = num; + FASTCONVERT conv = dbFastPutConvertRoutine[DBF_LONG][parser->dbrType]; + + if (parser->elems > 0) { + conv(&val32, parser->pdest, NULL); + parser->pdest += parser->dbrSize; + parser->elems--; + } + return 1; +} + +static int dbcj_double(void *ctx, double num) { + parseContext *parser = (parseContext *) ctx; + FASTCONVERT conv = dbFastPutConvertRoutine[DBF_DOUBLE][parser->dbrType]; + + if (parser->elems > 0) { + conv(&num, parser->pdest, NULL); + parser->pdest += parser->dbrSize; + parser->elems--; + } + return 1; +} + +static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) { + parseContext *parser = (parseContext *) ctx; + char *pdest = parser->pdest; + + /* Not attempting to handle char-array fields here, they need more + * metadata about the field than we have available at the moment. + */ + if (parser->dbrType != DBF_STRING) + return 0; /* Illegal */ + + if (parser->elems > 0) { + if (len > MAX_STRING_SIZE - 1) + len = MAX_STRING_SIZE - 1; + strncpy(pdest, (const char *) val, len); + pdest[len] = 0; + } + return 1; +} + +static int dbcj_start_map(void *ctx) { + return 0; /* Illegal */ +} + +static int dbcj_map_key(void *ctx, const unsigned char *key, unsigned int len) { + return 0; /* Illegal */ +} + +static int dbcj_end_map(void *ctx) { + return 0; /* Illegal */ +} + +static int dbcj_start_array(void *ctx) { + parseContext *parser = (parseContext *) ctx; + + parser->depth++; + return (parser->depth == 1); +} + +static int dbcj_end_array(void *ctx) { + parseContext *parser = (parseContext *) ctx; + + parser->depth--; + return (parser->depth == 0); +} + + +static yajl_callbacks dbcj_callbacks = { + dbcj_null, dbcj_boolean, dbcj_integer, dbcj_double, NULL, dbcj_string, + dbcj_start_map, dbcj_map_key, dbcj_end_map, + dbcj_start_array, dbcj_end_array +}; + +static const yajl_parser_config dbcj_config = + { 0, 0 }; /* allowComments = NO, checkUTF8 = NO */ + +long dbPutConvertJSON(const char *json, short dbrType, + void *pdest, long *pnRequest) +{ + parseContext context, *parser = &context; + yajl_alloc_funcs dbcj_alloc; + yajl_handle yh; + yajl_status ys; + size_t jlen = strlen(json); + long status; + + parser->depth = 0; + parser->dbrType = dbrType; + parser->dbrSize = dbValueSize(dbrType); + parser->pdest = pdest; + parser->elems = *pnRequest; + + yajl_set_default_alloc_funcs(&dbcj_alloc); + yh = yajl_alloc(&dbcj_callbacks, &dbcj_config, &dbcj_alloc, parser); + if (!yh) + return S_db_noMemory; + + ys = yajl_parse(yh, (const unsigned char *) json, (unsigned int) jlen); + if (ys == yajl_status_insufficient_data) + ys = yajl_parse_complete(yh); + + switch (ys) { + case yajl_status_ok: + *pnRequest -= parser->elems; + status = 0; + break; + + case yajl_status_error: { + unsigned char *err = yajl_get_error(yh, 1, + (const unsigned char *) json, (unsigned int) jlen); + fprintf(stderr, "dbPutConvertJSON: %s\n", err); + yajl_free_error(yh, err); + } + /* fall through */ + default: + status = S_db_badField; + } + + yajl_free(yh); + return status; +} + + diff --git a/src/ioc/db/dbConvertJSON.h b/src/ioc/db/dbConvertJSON.h new file mode 100644 index 000000000..11546d9ab --- /dev/null +++ b/src/ioc/db/dbConvertJSON.h @@ -0,0 +1,27 @@ +/*************************************************************************\ +* 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. +\*************************************************************************/ +/* dbConvertJSON.h */ + +#ifndef INC_dbConvertJSON_H +#define INC_dbConvertJSON_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* This name should probably be changed to inclue "array" */ +epicsShareFunc long dbPutConvertJSON(const char *json, short dbrType, + void *pdest, long *psize); + +#ifdef __cplusplus +} +#endif + +#endif /* INC_dbConvertJSON_H */ + diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c index 46c4b7ef6..0013d1b34 100644 --- a/src/ioc/db/dbDbLink.c +++ b/src/ioc/db/dbDbLink.c @@ -98,7 +98,6 @@ static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink) plink->value.pv_link.pvlMask = 0; plink->value.pv_link.lastGetdbrType = 0; plink->type = PV_LINK; - plink->lset = NULL; ellDelete(&pdbAddr->precord->bklnk, &plink->value.pv_link.backlinknode); dbLockSetSplit(locker, plink->precord, pdbAddr->precord); free(pdbAddr); @@ -332,8 +331,8 @@ static void dbDbScanFwdLink(struct link *plink) } static lset dbDb_lset = { - NULL, dbDbRemoveLink, + NULL, NULL, dbDbIsConnected, dbDbGetDBFtype, dbDbGetElements, dbDbGetValue, diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c index dfc02f4fe..111175276 100644 --- a/src/ioc/db/dbLink.c +++ b/src/ioc/db/dbLink.c @@ -145,8 +145,20 @@ long dbLoadLink(struct link *plink, short dbrType, void *pbuffer) { lset *plset = plink->lset; - if (plset->loadLink) - return plset->loadLink(plink, dbrType, pbuffer); + + if (plset->loadScalar) + return plset->loadScalar(plink, dbrType, pbuffer); + + return S_db_notFound; +} + +long dbLoadLinkArray(struct link *plink, short dbrType, void *pbuffer, + long *pnRequest) +{ + lset *plset = plink->lset; + + if (plset->loadArray) + return plset->loadArray(plink, dbrType, pbuffer, pnRequest); return S_db_notFound; } diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h index f33f6aee3..628483119 100644 --- a/src/ioc/db/dbLink.h +++ b/src/ioc/db/dbLink.h @@ -28,8 +28,10 @@ extern "C" { struct dbLocker; typedef struct lset { - long (*loadLink)(struct link *plink, short dbrType, void *pbuffer); void (*removeLink)(struct dbLocker *locker, struct link *plink); + long (*loadScalar)(struct link *plink, short dbrType, void *pbuffer); + long (*loadArray)(struct link *plink, short dbrType, void *pbuffer, + long *pnRequest); int (*isConnected)(const struct link *plink); int (*getDBFtype)(const struct link *plink); long (*getElements)(const struct link *plink, long *nelements); @@ -53,11 +55,13 @@ typedef struct lset { dbGetAlarm(link, NULL, sevr) epicsShareFunc void dbInitLink(struct link *plink, short dbfType); -epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType, - DBADDR *ptarget); +epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink, + short dbfType, DBADDR *ptarget); +epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink); epicsShareFunc long dbLoadLink(struct link *plink, short dbrType, void *pbuffer); -epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink); +epicsShareFunc long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer, + long *pnRequest); epicsShareFunc long dbGetNelements(const struct link *plink, long *nelements); epicsShareFunc int dbIsLinkConnected(const struct link *plink);