JSON Links implementation
The lnkConst.c implementation is not yet complete, no support for arrays of strings (JMOP). Link error messages should display their record & field name, which is not yet possible. The ability to embed links as parameters to other link types is not complete yet; this will be required for the calc link type. This code currently passes all existing tests, but additional tests are needed for the new functionality.
This commit is contained in:
@@ -25,6 +25,7 @@ INC += dbConvertJSON.h
|
||||
INC += dbDbLink.h
|
||||
INC += dbExtractArray.h
|
||||
INC += dbEvent.h
|
||||
INC += dbJLink.h
|
||||
INC += dbLink.h
|
||||
INC += dbLock.h
|
||||
INC += dbNotify.h
|
||||
@@ -73,6 +74,7 @@ dbCore_SRCS += dbConvertJSON.c
|
||||
dbCore_SRCS += dbDbLink.c
|
||||
dbCore_SRCS += dbFastLinkConv.c
|
||||
dbCore_SRCS += dbExtractArray.c
|
||||
dbCore_SRCS += dbJLink.c
|
||||
dbCore_SRCS += dbLink.c
|
||||
dbCore_SRCS += dbNotify.c
|
||||
dbCore_SRCS += dbScan.c
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
|
||||
@@ -46,28 +47,41 @@ void dbConstAddLink(struct link *plink)
|
||||
|
||||
static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer)
|
||||
{
|
||||
if (!plink->value.constantStr)
|
||||
return S_db_badField;
|
||||
const char *pstr = plink->value.constantStr;
|
||||
size_t len;
|
||||
|
||||
/* Constant scalars are always numeric */
|
||||
if (!pstr)
|
||||
return S_db_badField;
|
||||
len = strlen(pstr);
|
||||
|
||||
/* Choice values must be numeric */
|
||||
if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
|
||||
dbrType = DBF_USHORT;
|
||||
|
||||
if (*pstr == '[' && pstr[len-1] == ']') {
|
||||
/* Convert from JSON array */
|
||||
long nReq = 1;
|
||||
|
||||
return dbPutConvertJSON(pstr, dbrType, pbuffer, &nReq);
|
||||
}
|
||||
|
||||
return dbFastPutConvertRoutine[DBR_STRING][dbrType]
|
||||
(plink->value.constantStr, pbuffer, NULL);
|
||||
(pstr, pbuffer, NULL);
|
||||
}
|
||||
|
||||
static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer,
|
||||
long *pnReq)
|
||||
{
|
||||
if (!plink->value.constantStr)
|
||||
const char *pstr = plink->value.constantStr;
|
||||
|
||||
if (!pstr)
|
||||
return S_db_badField;
|
||||
|
||||
/* No support for arrays of choice types */
|
||||
/* Choice values must be numeric */
|
||||
if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
|
||||
return S_db_badField;
|
||||
dbrType = DBF_USHORT;
|
||||
|
||||
return dbPutConvertJSON(plink->value.constantStr, dbrType, pbuffer, pnReq);
|
||||
return dbPutConvertJSON(pstr, dbrType, pbuffer, pnReq);
|
||||
}
|
||||
|
||||
static long dbConstGetNelements(const struct link *plink, long *nelements)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "yajl_alloc.h"
|
||||
#include "yajl_parse.h"
|
||||
|
||||
@@ -23,7 +24,7 @@ typedef struct parseContext {
|
||||
int depth;
|
||||
short dbrType;
|
||||
short dbrSize;
|
||||
void *pdest;
|
||||
char *pdest;
|
||||
int elems;
|
||||
} parseContext;
|
||||
|
||||
@@ -67,8 +68,10 @@ static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) {
|
||||
/* 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)
|
||||
if (parser->dbrType != DBF_STRING) {
|
||||
errlogPrintf("dbPutConvertJSON: String provided, numeric value(s) expected\n");
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
if (parser->elems > 0) {
|
||||
if (len > parser->dbrSize - 1)
|
||||
@@ -82,6 +85,7 @@ static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) {
|
||||
}
|
||||
|
||||
static int dbcj_start_map(void *ctx) {
|
||||
errlogPrintf("dbPutConvertJSON: Map type not supported\n");
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
@@ -96,7 +100,9 @@ static int dbcj_end_map(void *ctx) {
|
||||
static int dbcj_start_array(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
|
||||
parser->depth++;
|
||||
if (++parser->depth > 1)
|
||||
errlogPrintf("dbPutConvertJSON: Embedded arrays not supported\n");
|
||||
|
||||
return (parser->depth == 1);
|
||||
}
|
||||
|
||||
|
||||
370
src/ioc/db/dbJLink.c
Normal file
370
src/ioc/db/dbJLink.c
Normal file
@@ -0,0 +1,370 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/* dbJLink.c */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "epicsAssert.h"
|
||||
#include "errlog.h"
|
||||
#include "yajl_alloc.h"
|
||||
#include "yajl_parse.h"
|
||||
|
||||
#define epicsExportSharedSybols
|
||||
#include "dbAccessDefs.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbJLink.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "link.h"
|
||||
|
||||
/* Change 'undef' to 'define' to turn on debug statements: */
|
||||
#undef DEBUG_JLINK
|
||||
|
||||
#ifdef DEBUG_JLINK
|
||||
int jlinkDebug = 10;
|
||||
# define IFDEBUG(n) \
|
||||
if (jlinkDebug >= n) /* block or statement */
|
||||
#else
|
||||
# define IFDEBUG(n) \
|
||||
if(0) /* Compiler will elide the block or statement */
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct parseContext {
|
||||
jlink *pjlink;
|
||||
jlink *product;
|
||||
struct link *plink;
|
||||
short dbfType;
|
||||
short jsonDepth;
|
||||
short linkDepth;
|
||||
unsigned key_is_link:1;
|
||||
} parseContext;
|
||||
|
||||
#define CALLIF(routine) !routine ? jlif_stop : routine
|
||||
|
||||
|
||||
static int dbjl_value(parseContext *parser, jlif_result result) {
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_value(%s@%p, %d)\n", pjlink->pif->name, pjlink, result);
|
||||
printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->linkDepth, parser->key_is_link);
|
||||
}
|
||||
|
||||
if (result == jlif_stop || parser->linkDepth > 0)
|
||||
return result;
|
||||
|
||||
parser->product = pjlink;
|
||||
parser->key_is_link = 0;
|
||||
parser->pjlink = pjlink->parent;
|
||||
|
||||
IFDEBUG(8)
|
||||
printf("dbjl_value: product = %p\n", pjlink);
|
||||
|
||||
return pjlink->pif->end_parse ? pjlink->pif->end_parse(pjlink)
|
||||
: jlif_continue;
|
||||
}
|
||||
|
||||
static int dbjl_null(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbjl_null(%s@%p)\n", pjlink->pif->name, pjlink);
|
||||
|
||||
assert(pjlink);
|
||||
return dbjl_value(parser, CALLIF(pjlink->pif->parse_null)(pjlink));
|
||||
}
|
||||
|
||||
static int dbjl_boolean(void *ctx, int val) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
assert(pjlink);
|
||||
return dbjl_value(parser, CALLIF(pjlink->pif->parse_boolean)(pjlink, val));
|
||||
}
|
||||
|
||||
static int dbjl_integer(void *ctx, long num) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbjl_integer(%s@%p, %ld)\n", pjlink->pif->name, pjlink, num);
|
||||
|
||||
assert(pjlink);
|
||||
return dbjl_value(parser, CALLIF(pjlink->pif->parse_integer)(pjlink, num));
|
||||
}
|
||||
|
||||
static int dbjl_double(void *ctx, double num) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbjl_double(%s@%p, %g)\n", pjlink->pif->name, pjlink, num);
|
||||
|
||||
assert(pjlink);
|
||||
return dbjl_value(parser, CALLIF(pjlink->pif->parse_double)(pjlink, num));
|
||||
}
|
||||
|
||||
static int dbjl_string(void *ctx, const unsigned char *val, unsigned len) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbjl_string(%s@%p, \"%.*s\")\n", pjlink->pif->name, pjlink, len, val);
|
||||
|
||||
assert(pjlink);
|
||||
return dbjl_value(parser,
|
||||
CALLIF(pjlink->pif->parse_string)(pjlink, (const char *) val, len));
|
||||
}
|
||||
|
||||
static int dbjl_start_map(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
jlif_key_result result;
|
||||
|
||||
if (!pjlink) {
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_start_map(NULL)\n");
|
||||
printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->linkDepth, parser->key_is_link);
|
||||
}
|
||||
|
||||
assert(parser->jsonDepth == 0);
|
||||
parser->jsonDepth++;
|
||||
parser->key_is_link = 1;
|
||||
return jlif_continue; /* Opening '{' */
|
||||
}
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_start_map(%s@%p)\n", pjlink->pif->name, pjlink);
|
||||
printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->linkDepth, parser->key_is_link);
|
||||
}
|
||||
|
||||
parser->linkDepth++;
|
||||
parser->jsonDepth++;
|
||||
result = CALLIF(pjlink->pif->parse_start_map)(pjlink);
|
||||
if (result == jlif_key_embed_link) {
|
||||
parser->key_is_link = 1;
|
||||
result = jlif_continue;
|
||||
}
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbjl_start_map -> %d\n", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
char link_name[MAX_LINK_NAME + 1];
|
||||
size_t lnlen = len;
|
||||
linkSup *linkSup;
|
||||
jlif *pjlif;
|
||||
jlif_result result;
|
||||
|
||||
if (!parser->key_is_link) {
|
||||
if (!pjlink) {
|
||||
errlogPrintf("dbJLinkInit: Illegal second link key '%.*s' seen for %s\n",
|
||||
len, key, parser->plink->precord->name);
|
||||
return jlif_stop;
|
||||
}
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_map_key(%s@%p, \"%.*s\")\n",
|
||||
pjlink->pif->name, pjlink, len, key);
|
||||
printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->linkDepth, parser->key_is_link);
|
||||
}
|
||||
|
||||
assert(parser->linkDepth > 0);
|
||||
return CALLIF(pjlink->pif->parse_map_key)(pjlink, (const char *) key, len);
|
||||
}
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_map_key(NULL, \"%.*s\")\n", len, key);
|
||||
printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->linkDepth, parser->key_is_link);
|
||||
}
|
||||
|
||||
if (lnlen > MAX_LINK_NAME)
|
||||
lnlen = MAX_LINK_NAME;
|
||||
strncpy(link_name, (const char *) key, lnlen);
|
||||
link_name[lnlen] = '\0';
|
||||
|
||||
linkSup = dbFindLinkSup(pdbbase, link_name);
|
||||
if (!linkSup) {
|
||||
errlogPrintf("dbJLinkInit: Link type '%s' not found for %s\n",
|
||||
link_name, parser->plink->precord->name);
|
||||
return jlif_stop;
|
||||
}
|
||||
|
||||
pjlif = linkSup->pjlif;
|
||||
if (!pjlif) {
|
||||
errlogPrintf("dbJLinkInit: Support for Link type '%s' not loaded\n",
|
||||
link_name);
|
||||
return jlif_stop;
|
||||
}
|
||||
|
||||
pjlink = pjlif->alloc_jlink(parser->plink);
|
||||
if (!pjlink) {
|
||||
errlogPrintf("dbJLinkInit: Out of memory\n");
|
||||
return jlif_stop;
|
||||
}
|
||||
pjlink->pif = pjlif;
|
||||
|
||||
if (parser->pjlink) {
|
||||
/* This is an embedded link */
|
||||
pjlink->parent = parser->pjlink;
|
||||
}
|
||||
|
||||
result = pjlif->start_parse ? pjlif->start_parse(pjlink) : jlif_continue;
|
||||
if (result == jlif_continue) {
|
||||
parser->pjlink = pjlink;
|
||||
|
||||
IFDEBUG(8)
|
||||
printf("dbjl_map_key: New %s@%p\n", pjlink->pif->name, pjlink);
|
||||
}
|
||||
else {
|
||||
pjlif->free_jlink(pjlink);
|
||||
}
|
||||
// FIXME Ensure link map has only one link key...
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbjl_map_key -> %d\n", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int dbjl_end_map(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
jlif_result result;
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_end_map(%s@%p)\n",
|
||||
pjlink ? pjlink->pif->name : "NULL", pjlink);
|
||||
printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->linkDepth, parser->key_is_link);
|
||||
}
|
||||
|
||||
parser->jsonDepth--;
|
||||
if (parser->linkDepth > 0) {
|
||||
parser->linkDepth--;
|
||||
|
||||
result = dbjl_value(parser, CALLIF(pjlink->pif->parse_end_map)(pjlink));
|
||||
}
|
||||
else {
|
||||
result = jlif_continue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int dbjl_start_array(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_start_array(%s@%p)\n", pjlink->pif->name, pjlink);
|
||||
printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->linkDepth, parser->key_is_link);
|
||||
}
|
||||
|
||||
assert(pjlink);
|
||||
parser->linkDepth++;
|
||||
parser->jsonDepth++;
|
||||
return CALLIF(pjlink->pif->parse_start_array)(pjlink);
|
||||
}
|
||||
|
||||
static int dbjl_end_array(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_end_array(%s@%p)\n", pjlink->pif->name, pjlink);
|
||||
printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->linkDepth, parser->key_is_link);
|
||||
}
|
||||
|
||||
assert(pjlink);
|
||||
parser->linkDepth--;
|
||||
parser->jsonDepth--;
|
||||
return dbjl_value(parser, CALLIF(pjlink->pif->parse_end_array)(pjlink));
|
||||
}
|
||||
|
||||
static yajl_callbacks dbjl_callbacks = {
|
||||
dbjl_null, dbjl_boolean, dbjl_integer, dbjl_double, NULL, dbjl_string,
|
||||
dbjl_start_map, dbjl_map_key, dbjl_end_map, dbjl_start_array, dbjl_end_array
|
||||
};
|
||||
|
||||
static const yajl_parser_config dbjl_config =
|
||||
{ 0, 0 }; /* allowComments = NO, checkUTF8 = NO */
|
||||
|
||||
long dbJLinkInit(struct link *plink, short dbfType)
|
||||
{
|
||||
parseContext context, *parser = &context;
|
||||
yajl_alloc_funcs dbjl_allocs;
|
||||
yajl_handle yh;
|
||||
yajl_status ys;
|
||||
const char *json = plink->value.json.string;
|
||||
size_t jlen = strlen(json);
|
||||
long status;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbJLinkInit(\"%s.????\", %d)\n", plink->precord->name, dbfType);
|
||||
|
||||
parser->pjlink = NULL;
|
||||
parser->product = NULL;
|
||||
parser->plink = plink;
|
||||
parser->dbfType = dbfType;
|
||||
parser->jsonDepth = 0;
|
||||
parser->linkDepth = 0;
|
||||
parser->key_is_link = 0;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbJLinkInit: jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->linkDepth, parser->key_is_link);
|
||||
|
||||
yajl_set_default_alloc_funcs(&dbjl_allocs);
|
||||
yh = yajl_alloc(&dbjl_callbacks, &dbjl_config, &dbjl_allocs, parser);
|
||||
if (!yh)
|
||||
return S_db_noMemory;
|
||||
|
||||
ys = yajl_parse(yh, (const unsigned char *) json, (unsigned) jlen);
|
||||
if (ys == yajl_status_insufficient_data)
|
||||
ys = yajl_parse_complete(yh);
|
||||
|
||||
switch (ys) {
|
||||
unsigned char *err;
|
||||
jlink *pjlink;
|
||||
|
||||
case yajl_status_ok:
|
||||
assert(parser->jsonDepth == 0);
|
||||
pjlink = parser->product;
|
||||
assert(pjlink);
|
||||
plink->value.json.jlink = pjlink;
|
||||
plink->lset = pjlink->pif->get_lset(pjlink);
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
case yajl_status_error:
|
||||
err = yajl_get_error(yh, 1, (const unsigned char *) json, (unsigned) jlen);
|
||||
errlogPrintf("dbJLinkInit: %s\n", err);
|
||||
yajl_free_error(yh, err);
|
||||
/* fall through */
|
||||
default:
|
||||
status = S_db_badField;
|
||||
}
|
||||
|
||||
yajl_free(yh);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
70
src/ioc/db/dbJLink.h
Normal file
70
src/ioc/db/dbJLink.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/* dbJLink.h */
|
||||
|
||||
#ifndef INC_dbJLink_H
|
||||
#define INC_dbJLink_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <shareLib.h>
|
||||
|
||||
/* Limit for link name key length */
|
||||
#define MAX_LINK_NAME 15
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
jlif_stop = 0,
|
||||
jlif_continue = 1
|
||||
} jlif_result;
|
||||
|
||||
typedef enum {
|
||||
jlif_key_stop = jlif_stop,
|
||||
jlif_key_continue = jlif_continue,
|
||||
jlif_key_embed_link
|
||||
} jlif_key_result;
|
||||
|
||||
struct link;
|
||||
struct lset;
|
||||
typedef struct jlink jlink;
|
||||
|
||||
typedef struct jlif {
|
||||
const char *name;
|
||||
jlink* (*alloc_jlink)(struct link *);
|
||||
void (*free_jlink)(jlink *);
|
||||
jlif_result (*start_parse)(jlink *);
|
||||
jlif_result (*parse_null)(jlink *);
|
||||
jlif_result (*parse_boolean)(jlink *, int val);
|
||||
jlif_result (*parse_integer)(jlink *, long num);
|
||||
jlif_result (*parse_double)(jlink *, double num);
|
||||
jlif_result (*parse_string)(jlink *, const char *val, size_t len);
|
||||
jlif_key_result (*parse_start_map)(jlink *);
|
||||
jlif_result (*parse_map_key)(jlink *, const char *key, size_t len);
|
||||
jlif_result (*parse_end_map)(jlink *);
|
||||
jlif_result (*parse_start_array)(jlink *);
|
||||
jlif_result (*parse_end_array)(jlink *);
|
||||
jlif_result (*end_parse)(jlink *);
|
||||
struct lset* (*get_lset)(const jlink *);
|
||||
void (*report)(const jlink *);
|
||||
} jlif;
|
||||
|
||||
typedef struct jlink {
|
||||
jlif *pif;
|
||||
jlink *parent;
|
||||
/* Link types extend or embed this structure for private storage */
|
||||
} jlink;
|
||||
|
||||
epicsShareFunc long dbJLinkInit(struct link *plink, short dbfType);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INC_dbJLink_H */
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "dbDbLink.h"
|
||||
#include "db_field_log.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbJLink.h"
|
||||
#include "dbLink.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbScan.h"
|
||||
@@ -77,6 +78,11 @@ void dbInitLink(struct link *plink, short dbfType)
|
||||
return;
|
||||
}
|
||||
|
||||
if (plink->type == JSON_LINK) {
|
||||
dbJLinkInit(plink, dbfType);
|
||||
return;
|
||||
}
|
||||
|
||||
if (plink->type != PV_LINK)
|
||||
return;
|
||||
|
||||
@@ -120,6 +126,15 @@ void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
|
||||
return;
|
||||
}
|
||||
|
||||
if (plink->type == JSON_LINK) {
|
||||
/*
|
||||
* FIXME: Can't create DB links as dbJLink types yet,
|
||||
* dbLock.c doesn't have any way to find/track them.
|
||||
*/
|
||||
dbJLinkInit(plink, dbfType);
|
||||
return;
|
||||
}
|
||||
|
||||
if (plink->type != PV_LINK)
|
||||
return;
|
||||
|
||||
|
||||
@@ -941,7 +941,9 @@ static void printBuffer(
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < no_elements; i+= MAXLINE - 5) {
|
||||
sprintf(pmsg, " \"%.*s\"", MAXLINE - 5, (char *)pbuffer + i);
|
||||
int width = no_elements - i;
|
||||
if (width > MAXLINE - 5) width = MAXLINE - 5;
|
||||
sprintf(pmsg, " \"%.*s\"", width, (char *)pbuffer + i);
|
||||
if (i + MAXLINE - 5 < no_elements) strcat(pmsg, " +");
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ typedef struct devSup {
|
||||
typedef struct linkSup {
|
||||
ELLNODE node;
|
||||
char *name;
|
||||
char *lset_name;
|
||||
struct lset *lset;
|
||||
char *jlif_name;
|
||||
struct jlif *pjlif;
|
||||
} linkSup;
|
||||
|
||||
typedef struct dbDeviceMenu {
|
||||
|
||||
@@ -75,7 +75,7 @@ static void dbRecordtypeFieldItem(char *name,char *value);
|
||||
static void dbDevice(char *recordtype,char *linktype,
|
||||
char *dsetname,char *choicestring);
|
||||
static void dbDriver(char *name);
|
||||
static void dbLinkType(char *name, char *lset_name);
|
||||
static void dbLinkType(char *name, char *jlif_name);
|
||||
static void dbRegistrar(char *name);
|
||||
static void dbFunction(char *name);
|
||||
static void dbVariable(char *name, char *type);
|
||||
@@ -786,7 +786,7 @@ static void dbDriver(char *name)
|
||||
ellAdd(&pdbbase->drvList,&pdrvSup->node);
|
||||
}
|
||||
|
||||
static void dbLinkType(char *name, char *lset_name)
|
||||
static void dbLinkType(char *name, char *jlif_name)
|
||||
{
|
||||
linkSup *pLinkSup;
|
||||
GPHENTRY *pgphentry;
|
||||
@@ -797,7 +797,7 @@ static void dbLinkType(char *name, char *lset_name)
|
||||
}
|
||||
pLinkSup = dbCalloc(1,sizeof(linkSup));
|
||||
pLinkSup->name = epicsStrDup(name);
|
||||
pLinkSup->lset_name = epicsStrDup(lset_name);
|
||||
pLinkSup->jlif_name = epicsStrDup(jlif_name);
|
||||
pgphentry = gphAdd(pdbbase->pgpHash, pLinkSup->name, &pdbbase->linkList);
|
||||
if (!pgphentry) {
|
||||
yyerrorAbort("gphAdd failed");
|
||||
@@ -1053,7 +1053,7 @@ static void dbRecordField(char *name,char *value)
|
||||
value++;
|
||||
value[strlen(value) - 1] = 0;
|
||||
}
|
||||
dbTranslateEscape(value, value); /* yuck: in-place, but safe */
|
||||
dbTranslateEscape(value, value); /* in-place; safe & legal */
|
||||
status = dbPutString(pdbentry,value);
|
||||
if(status) {
|
||||
epicsPrintf("Can't set \"%s.%s\" to \"%s\"\n",
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "special.h"
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbJLink.h"
|
||||
|
||||
int dbStaticDebug = 0;
|
||||
static char *pNullString = "";
|
||||
@@ -122,7 +123,11 @@ 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_LINK: parm = plink->value.json.string; break;
|
||||
case JSON_LINK:
|
||||
if (plink->value.json.jlink)
|
||||
plink->value.json.jlink->pif->free_jlink(plink->value.json.jlink);
|
||||
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;
|
||||
@@ -560,7 +565,7 @@ void dbFreeBase(dbBase *pdbbase)
|
||||
pdrvSup = pdrvSupNext;
|
||||
}
|
||||
while ((plinkSup = (linkSup *) ellGet(&pdbbase->linkList))) {
|
||||
free(plinkSup->lset_name);
|
||||
free(plinkSup->jlif_name);
|
||||
free(plinkSup->name);
|
||||
free(plinkSup);
|
||||
}
|
||||
@@ -1086,7 +1091,7 @@ long dbWriteLinkFP(DBBASE *pdbbase, FILE *fp)
|
||||
}
|
||||
for (plinkSup = (linkSup *) ellFirst(&pdbbase->linkList);
|
||||
plinkSup; plinkSup = (linkSup *) ellNext(&plinkSup->node)) {
|
||||
fprintf(fp, "link(%s,%s)\n", plinkSup->name, plinkSup->lset_name);
|
||||
fprintf(fp, "link(%s,%s)\n", plinkSup->name, plinkSup->jlif_name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -2267,9 +2272,8 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
|
||||
|
||||
/* Check for braces => JSON */
|
||||
if (*str == '{' && str[len-1] == '}') {
|
||||
/* FIXME Parse JSON object here */
|
||||
pinfo->ltype = JSON_LINK;
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for other HW link types */
|
||||
@@ -2337,7 +2341,6 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
|
||||
/* Link may be an array constant */
|
||||
if (pstr[0] == '[' && pstr[len-1] == ']' &&
|
||||
(strchr(pstr, ',') || strchr(pstr, '"'))) {
|
||||
/* FIXME Parse JSON array here */
|
||||
pinfo->ltype = CONSTANT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -87,9 +87,10 @@ struct pv_link {
|
||||
short lastGetdbrType; /* last dbrType for DB or CA get */
|
||||
};
|
||||
|
||||
struct jlink;
|
||||
struct json_link {
|
||||
char *string;
|
||||
/* ... */
|
||||
struct jlink *jlink;
|
||||
};
|
||||
|
||||
/* structure of a VME io channel */
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
#include "recSup.h"
|
||||
#include "registryDeviceSupport.h"
|
||||
#include "registryDriverSupport.h"
|
||||
#include "registryJLinks.h"
|
||||
#include "registryRecordType.h"
|
||||
#include "rsrv.h"
|
||||
|
||||
@@ -79,6 +80,7 @@ static enum {
|
||||
/* define forward references*/
|
||||
static int checkDatabase(dbBase *pdbbase);
|
||||
static void initDrvSup(void);
|
||||
static void initJLinks(void);
|
||||
static void initRecSup(void);
|
||||
static void initDevSup(void);
|
||||
static void finishDevSup(void);
|
||||
@@ -145,6 +147,7 @@ static int iocBuild_2(void)
|
||||
{
|
||||
initHookAnnounce(initHookAfterCaLinkInit);
|
||||
|
||||
initJLinks();
|
||||
initDrvSup();
|
||||
initHookAnnounce(initHookAfterInitDrvSup);
|
||||
|
||||
@@ -374,6 +377,22 @@ static void initDrvSup(void) /* Locate all driver support entry tables */
|
||||
}
|
||||
}
|
||||
|
||||
static void initJLinks(void)
|
||||
{
|
||||
linkSup *plinkSup;
|
||||
|
||||
for (plinkSup = (linkSup *)ellFirst(&pdbbase->linkList); plinkSup;
|
||||
plinkSup = (linkSup *)ellNext(&plinkSup->node)) {
|
||||
jlif *pjlif = registryJLinkFind(plinkSup->name);
|
||||
|
||||
if (!pjlif) {
|
||||
errlogPrintf("iocInit: JLink %s not found\n", plinkSup->name);
|
||||
continue;
|
||||
}
|
||||
plinkSup->pjlif = pjlif;
|
||||
}
|
||||
}
|
||||
|
||||
static void initRecSup(void)
|
||||
{
|
||||
dbRecordType *pdbRecordType;
|
||||
|
||||
@@ -14,6 +14,7 @@ SRC_DIRS += $(IOCDIR)/registry
|
||||
INC += registryRecordType.h
|
||||
INC += registryDeviceSupport.h
|
||||
INC += registryDriverSupport.h
|
||||
INC += registryJLinks.h
|
||||
INC += registryFunction.h
|
||||
INC += registryCommon.h
|
||||
INC += registryIocRegister.h
|
||||
@@ -21,6 +22,7 @@ INC += registryIocRegister.h
|
||||
dbCore_SRCS += registryRecordType.c
|
||||
dbCore_SRCS += registryDeviceSupport.c
|
||||
dbCore_SRCS += registryDriverSupport.c
|
||||
dbCore_SRCS += registryJLinks.c
|
||||
dbCore_SRCS += registryFunction.c
|
||||
dbCore_SRCS += registryCommon.c
|
||||
dbCore_SRCS += registryIocRegister.c
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "registryCommon.h"
|
||||
#include "registryDeviceSupport.h"
|
||||
#include "registryDriverSupport.h"
|
||||
#include "registryJLinks.h"
|
||||
|
||||
|
||||
void registerRecordTypes(DBBASE *pbase, int nRecordTypes,
|
||||
@@ -76,3 +77,16 @@ void registerDrivers(DBBASE *pbase, int nDrivers,
|
||||
}
|
||||
}
|
||||
|
||||
void registerJLinks(DBBASE *pbase, int nLinks, jlif * const *jlifsl)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nLinks; i++) {
|
||||
if (registryJLinkFind(jlifsl[i]->name)) continue;
|
||||
if (!registryJLinkAdd(jlifsl[i])) {
|
||||
errlogPrintf("registryJLinkAdd failed %s\n",
|
||||
jlifsl[i]->name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "dbStaticLib.h"
|
||||
#include "devSup.h"
|
||||
#include "dbJLink.h"
|
||||
#include "registryRecordType.h"
|
||||
#include "shareLib.h"
|
||||
|
||||
@@ -28,6 +29,8 @@ epicsShareFunc void registerDevices(
|
||||
epicsShareFunc void registerDrivers(
|
||||
DBBASE *pbase, int nDrivers,
|
||||
const char * const *driverSupportNames, struct drvet * const *drvsl);
|
||||
epicsShareFunc void registerJLinks(
|
||||
DBBASE *pbase, int nDrivers, jlif * const *jlifsl);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
27
src/ioc/registry/registryJLinks.c
Normal file
27
src/ioc/registry/registryJLinks.c
Normal file
@@ -0,0 +1,27 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/* registryJLinks.c */
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "registry.h"
|
||||
#include "registryJLinks.h"
|
||||
#include "dbJLink.h"
|
||||
|
||||
static void *registryID = "JSON link types";
|
||||
|
||||
|
||||
epicsShareFunc int registryJLinkAdd(struct jlif *pjlif)
|
||||
{
|
||||
return registryAdd(registryID, pjlif->name, pjlif);
|
||||
}
|
||||
|
||||
epicsShareFunc jlif * registryJLinkFind(const char *name)
|
||||
{
|
||||
return registryFind(registryID, name);
|
||||
}
|
||||
28
src/ioc/registry/registryJLinks.h
Normal file
28
src/ioc/registry/registryJLinks.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef INC_registryJLinks_H
|
||||
#define INC_registryJLinks_H
|
||||
|
||||
#include "dbJLink.h"
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
epicsShareFunc int registryJLinkAdd(jlif *pjlif);
|
||||
epicsShareFunc jlif * registryJLinkFind(const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* INC_registryDriverSupport_H */
|
||||
@@ -11,7 +11,7 @@ SRC_DIRS += $(STDDIR)/link
|
||||
|
||||
DBD += links.dbd
|
||||
|
||||
# dbRecStd_SRCS += ...
|
||||
dbRecStd_SRCS += lnkConst.c
|
||||
|
||||
HTMLS += links.html
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
=head1 Link Types
|
||||
=head1 JSON Links
|
||||
|
||||
Links are an extensible mechanism for adding new kinds of database link,
|
||||
using JSON for link addresses.
|
||||
JSON Links are an extensible mechanism for adding new kinds of database link,
|
||||
using JSON for the link address.
|
||||
The following link types are available in this release:
|
||||
|
||||
=over
|
||||
@@ -12,6 +12,8 @@ The following link types are available in this release:
|
||||
|
||||
=item * L<Channel Access|/"Channel Access Link ca">
|
||||
|
||||
=item * L<Calc|/"Calculation Link calc">
|
||||
|
||||
=back
|
||||
|
||||
=head2 Using Links
|
||||
@@ -21,35 +23,36 @@ must appear inside a pair of braces C< {} > expressed as a JSON
|
||||
(L<JavaScript Object Notation|http://www.json.org/>) object, which allows link
|
||||
parameters to be defined as needed.
|
||||
|
||||
Note that due to the required presence of the double-quote characters in the
|
||||
JSON strings in a link field value string in a database file, it will usually
|
||||
be necessary to escape all double-quote characters in the JSON object by
|
||||
preceding them with a backslash C< \ > character.
|
||||
Database configuration tools that support this link mechanism must be careful
|
||||
to handle these escapes correctly on reading and writing string values from/to
|
||||
a .db file.
|
||||
|
||||
=head2 Filter Reference
|
||||
=head2 Link Type Reference
|
||||
|
||||
=cut
|
||||
|
||||
link(const,lsetConst)
|
||||
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 initialization, which results in
|
||||
the constant value being loaded into the target field at that time.
|
||||
|
||||
=head4 Parameters
|
||||
|
||||
...
|
||||
A const link takes a parameter which may be an integer, double or string, or an array of
|
||||
those types. If an array contains both integers and double values the integers will be
|
||||
promoted to doubles. Mixing strings and numbers in an array will result in an error.
|
||||
|
||||
=head4 Example
|
||||
=head4 Examples
|
||||
|
||||
...
|
||||
{const: 3.14159265358979}
|
||||
{const: "Pi"}
|
||||
{const: [1, 2.718281828459, 3.14159265358979]}
|
||||
{const: ["One", "e", "Pi"]}
|
||||
|
||||
=cut
|
||||
|
||||
link(db,lsetDatabase)
|
||||
#link(db, lnkDbIf)
|
||||
|
||||
=head3 Database Link C<"db">
|
||||
|
||||
@@ -65,7 +68,7 @@ link(db,lsetDatabase)
|
||||
|
||||
=cut
|
||||
|
||||
link(ca,lsetChannelAccess)
|
||||
#link(ca, lnkCaIf)
|
||||
|
||||
=head3 Channel Access Link C<"ca">
|
||||
|
||||
@@ -90,3 +93,19 @@ link(ca,lsetChannelAccess)
|
||||
...
|
||||
|
||||
=cut
|
||||
|
||||
#link(calc, lnkCalcIf)
|
||||
|
||||
=head3 Calculation Link C<"calc">
|
||||
|
||||
...
|
||||
|
||||
=head4 Parameters
|
||||
|
||||
...
|
||||
|
||||
=head4 Example
|
||||
|
||||
...
|
||||
|
||||
=cut
|
||||
|
||||
412
src/std/link/lnkConst.c
Normal file
412
src/std/link/lnkConst.c
Normal file
@@ -0,0 +1,412 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/* lnkConst.c */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsTypes.h"
|
||||
#include "dbAccessDefs.h"
|
||||
#include "dbConvertFast.h"
|
||||
#include "dbLink.h"
|
||||
#include "dbJLink.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
|
||||
/* Change 'undef' to 'define' to turn on debug statements: */
|
||||
#undef DEBUG_LINK
|
||||
|
||||
#ifdef DEBUG_LINK
|
||||
int lnkConstDebug = 10;
|
||||
# define IFDEBUG(n) \
|
||||
if (lnkConstDebug >= n) /* block or statement */
|
||||
#else
|
||||
# define IFDEBUG(n) \
|
||||
if(0) /* Compiler will elide the block or statement */
|
||||
#endif
|
||||
|
||||
typedef long (*FASTCONVERT)();
|
||||
|
||||
typedef struct clink {
|
||||
struct jlink jlink; /* embedded */
|
||||
int nElems;
|
||||
enum {s0, si32, sf64, sc40, a0, ai32, af64, ac40} type;
|
||||
union {
|
||||
epicsInt32 scalar_integer;
|
||||
epicsFloat64 scalar_double;
|
||||
char * scalar_string;
|
||||
void *pmem;
|
||||
epicsInt32 *pintegers;
|
||||
epicsFloat64 *pdoubles;
|
||||
char **pstrings;
|
||||
} value;
|
||||
} clink;
|
||||
|
||||
static lset lnkConst_lset;
|
||||
|
||||
|
||||
/*************************** jlif Routines **************************/
|
||||
|
||||
static jlink* lnkConst_alloc(struct link *plink) {
|
||||
clink *clink = calloc(1, sizeof(struct clink));
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_alloc()\n");
|
||||
|
||||
clink->type = s0;
|
||||
clink->nElems = 0;
|
||||
clink->value.pmem = NULL;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_alloc -> const@%p\n", clink);
|
||||
|
||||
return &clink->jlink;
|
||||
}
|
||||
|
||||
static void lnkConst_free(jlink *pjlink) {
|
||||
clink *clink = CONTAINER(pjlink, struct clink, jlink);
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_free(const@%p)\n", pjlink);
|
||||
|
||||
switch (clink->type) {
|
||||
int i;
|
||||
case ac40:
|
||||
for (i=0; i<clink->nElems; i++)
|
||||
free(clink->value.pstrings[i]);
|
||||
/* fall through */
|
||||
case ai32:
|
||||
case af64:
|
||||
free(clink->value.pmem);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(clink);
|
||||
}
|
||||
|
||||
static jlif_result lnkConst_integer(jlink *pjlink, long num) {
|
||||
clink *clink = CONTAINER(pjlink, struct clink, jlink);
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_integer(const@%p, %ld)\n", pjlink, num);
|
||||
|
||||
switch (clink->type) {
|
||||
void *buf;
|
||||
int nElems;
|
||||
|
||||
case s0:
|
||||
clink->nElems = 1;
|
||||
clink->type = si32;
|
||||
clink->value.scalar_integer = num;
|
||||
break;
|
||||
|
||||
case a0:
|
||||
clink->type = ai32;
|
||||
/* fall thorough */
|
||||
case ai32:
|
||||
nElems = clink->nElems + 1;
|
||||
buf = realloc(clink->value.pmem, nElems * sizeof(epicsInt32));
|
||||
if (!buf) break;
|
||||
clink->value.pmem = buf;
|
||||
clink->value.pintegers[clink->nElems] = num;
|
||||
clink->nElems = nElems;
|
||||
break;
|
||||
|
||||
case af64:
|
||||
nElems = clink->nElems + 1;
|
||||
buf = realloc(clink->value.pmem, nElems * sizeof(epicsFloat64));
|
||||
if (!buf) break;
|
||||
clink->value.pmem = buf;
|
||||
clink->value.pdoubles[clink->nElems++] = num;
|
||||
break;
|
||||
|
||||
case ac40:
|
||||
errlogPrintf("lnkConst: Mixed data types in array\n");
|
||||
/* FIXME ??? */
|
||||
default:
|
||||
return jlif_stop;
|
||||
}
|
||||
return jlif_continue;
|
||||
}
|
||||
|
||||
static jlif_result lnkConst_boolean(jlink *pjlink, int val) {
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_boolean(const@%p, %d)\n", pjlink, val);
|
||||
|
||||
return lnkConst_integer(pjlink, val);
|
||||
}
|
||||
|
||||
static jlif_result lnkConst_double(jlink *pjlink, double num) {
|
||||
clink *clink = CONTAINER(pjlink, struct clink, jlink);
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_double(const@%p, %g)\n", pjlink, num);
|
||||
|
||||
switch (clink->type) {
|
||||
epicsFloat64 *f64buf;
|
||||
int nElems, i;
|
||||
|
||||
case s0:
|
||||
clink->nElems = 1;
|
||||
clink->type = sf64;
|
||||
clink->value.scalar_double = num;
|
||||
break;
|
||||
|
||||
case a0:
|
||||
clink->type = af64;
|
||||
/* fall thorough */
|
||||
case af64:
|
||||
nElems = clink->nElems + 1;
|
||||
f64buf = realloc(clink->value.pmem, nElems * sizeof(epicsFloat64));
|
||||
if (!f64buf) break;
|
||||
clink->value.pdoubles = f64buf;
|
||||
clink->value.pdoubles[clink->nElems++] = num;
|
||||
break;
|
||||
|
||||
case ai32: /* promote earlier ai32 values to af64 */
|
||||
f64buf = calloc(clink->nElems + 1, sizeof(epicsFloat64));
|
||||
if (!f64buf) break;
|
||||
for (i = 0; i < clink->nElems; i++) {
|
||||
f64buf[i] = clink->value.pintegers[i];
|
||||
}
|
||||
f64buf[clink->nElems++] = num;
|
||||
free(clink->value.pmem);
|
||||
clink->value.pdoubles = f64buf;
|
||||
clink->type = af64;
|
||||
break;
|
||||
|
||||
case ac40:
|
||||
errlogPrintf("lnkConst: Mixed data types in array\n");
|
||||
/* FIXME ??? */
|
||||
default:
|
||||
return jlif_stop;
|
||||
}
|
||||
|
||||
return jlif_continue;
|
||||
}
|
||||
|
||||
static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len) {
|
||||
clink *clink = CONTAINER(pjlink, struct clink, jlink);
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_string(const@%p, \"%.*s\")\n", clink, (int) len, val);
|
||||
|
||||
if (len > MAX_STRING_SIZE)
|
||||
len = MAX_STRING_SIZE;
|
||||
|
||||
if (clink->type == s0) {
|
||||
char *buf = malloc(len + 1);
|
||||
|
||||
if (!buf)
|
||||
return jlif_stop;
|
||||
|
||||
strncpy(buf, val, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
clink->nElems = 1;
|
||||
clink->type = sc40;
|
||||
clink->value.scalar_string = buf;
|
||||
return jlif_continue;
|
||||
}
|
||||
/* FIXME Implement a0 and ac40 */
|
||||
/* FIXME How to handle ai32 and af64? */
|
||||
errlogPrintf("lnkConst: Mixed data types in array\n");
|
||||
|
||||
return jlif_stop;
|
||||
}
|
||||
|
||||
static jlif_result lnkConst_start_array(jlink *pjlink) {
|
||||
clink *clink = CONTAINER(pjlink, struct clink, jlink);
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_start_array(const@%p)\n", pjlink);
|
||||
|
||||
if (clink->type != s0) {
|
||||
errlogPrintf("lnkConst: Embedded array value\n");
|
||||
return jlif_stop;
|
||||
}
|
||||
|
||||
clink->type = a0;
|
||||
return jlif_continue;
|
||||
}
|
||||
|
||||
static jlif_result lnkConst_end_array(jlink *pjlink) {
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_end_array(const@%p)\n", pjlink);
|
||||
|
||||
return jlif_continue;
|
||||
}
|
||||
|
||||
static struct lset* lnkConst_get_lset(const jlink *pjlink) {
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_get_lset(const@%p)\n", pjlink);
|
||||
|
||||
return &lnkConst_lset;
|
||||
}
|
||||
|
||||
static void lnkConst_report(const jlink *pjlink) {
|
||||
clink *clink = CONTAINER(pjlink, struct clink, jlink);
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_report(const@%p)\n", clink);
|
||||
|
||||
/* FIXME Implement! */
|
||||
}
|
||||
|
||||
/*************************** lset Routines **************************/
|
||||
|
||||
static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer)
|
||||
{
|
||||
clink *clink = CONTAINER(plink->value.json.jlink, struct clink, jlink);
|
||||
long status;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_loadScalar(const@%p, %d, %p)\n",
|
||||
clink, dbrType, pbuffer);
|
||||
|
||||
switch (clink->type) {
|
||||
case si32:
|
||||
status = dbFastPutConvertRoutine[DBF_LONG][dbrType]
|
||||
(&clink->value.scalar_integer, pbuffer, NULL);
|
||||
break;
|
||||
|
||||
case sf64:
|
||||
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
|
||||
(&clink->value.scalar_double, pbuffer, NULL);
|
||||
break;
|
||||
|
||||
case sc40:
|
||||
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
|
||||
(clink->value.scalar_string, pbuffer, NULL);
|
||||
break;
|
||||
|
||||
case ai32:
|
||||
status = dbFastPutConvertRoutine[DBF_LONG][dbrType]
|
||||
(clink->value.pintegers, pbuffer, NULL);
|
||||
break;
|
||||
|
||||
case af64:
|
||||
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
|
||||
(clink->value.pdoubles, pbuffer, NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = S_db_badField;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
|
||||
long *pnReq)
|
||||
{
|
||||
clink *clink = CONTAINER(plink->value.json.jlink, struct clink, jlink);
|
||||
short dbrSize = dbValueSize(dbrType);
|
||||
char *pdest = pbuffer;
|
||||
int nElems = clink->nElems;
|
||||
FASTCONVERT conv;
|
||||
long status;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_loadArray(const@%p, %d, %p, (%ld))\n",
|
||||
clink, dbrType, pbuffer, *pnReq);
|
||||
|
||||
if (nElems > *pnReq)
|
||||
nElems = *pnReq;
|
||||
|
||||
switch (clink->type) {
|
||||
int i;
|
||||
|
||||
case si32:
|
||||
status = dbFastPutConvertRoutine[DBF_LONG][dbrType]
|
||||
(&clink->value.scalar_integer, pdest, NULL);
|
||||
break;
|
||||
|
||||
case sf64:
|
||||
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
|
||||
(&clink->value.scalar_double, pdest, NULL);
|
||||
break;
|
||||
|
||||
case sc40:
|
||||
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
|
||||
(clink->value.scalar_string, pbuffer, NULL);
|
||||
break;
|
||||
|
||||
case ai32:
|
||||
conv = dbFastPutConvertRoutine[DBF_LONG][dbrType];
|
||||
for (i = 0; i < nElems; i++) {
|
||||
conv(&clink->value.pintegers[i], pdest, NULL);
|
||||
pdest += dbrSize;
|
||||
}
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
case af64:
|
||||
conv = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType];
|
||||
for (i = 0; i < nElems; i++) {
|
||||
conv(&clink->value.pdoubles[i], pdest, NULL);
|
||||
pdest += dbrSize;
|
||||
}
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
status = S_db_badField;
|
||||
}
|
||||
*pnReq = nElems;
|
||||
return status;
|
||||
}
|
||||
|
||||
static long lnkConst_getNelements(const struct link *plink, long *nelements)
|
||||
{
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_getNelements(const@%p, (%ld))\n",
|
||||
plink->value.json.jlink, *nelements);
|
||||
|
||||
*nelements = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
|
||||
{
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_loadScalar(const@%p, %d, %p, ... (%ld))\n",
|
||||
plink->value.json.jlink, dbrType, pbuffer, *pnRequest);
|
||||
|
||||
if (pnRequest)
|
||||
*pnRequest = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/************************* Interface Tables *************************/
|
||||
|
||||
static lset lnkConst_lset = {
|
||||
1, 0, /* Constant, not Volatile */
|
||||
NULL, lnkConst_loadScalar, lnkConst_loadArray, NULL,
|
||||
NULL, lnkConst_getNelements, lnkConst_getValue,
|
||||
NULL, NULL, NULL,
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static jlif lnkConstIf = {
|
||||
"const", lnkConst_alloc, lnkConst_free, NULL,
|
||||
NULL, lnkConst_boolean, lnkConst_integer, lnkConst_double, lnkConst_string,
|
||||
NULL, NULL, NULL, lnkConst_start_array, lnkConst_end_array,
|
||||
NULL, lnkConst_get_lset, lnkConst_report
|
||||
};
|
||||
epicsExportAddress(jlif, lnkConstIf);
|
||||
|
||||
@@ -3,8 +3,8 @@ use DBD::Base;
|
||||
@ISA = qw(DBD::Base);
|
||||
|
||||
sub init {
|
||||
my ($this, $name, $lset) = @_;
|
||||
$this->SUPER::init($lset, "link support (lset)");
|
||||
my ($this, $name, $jlif) = @_;
|
||||
$this->SUPER::init($jlif, "link support (jlif)");
|
||||
$this->{KEY} = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -159,6 +159,20 @@ if (%drivers) {
|
||||
print $out "};\n\n";
|
||||
}
|
||||
|
||||
my %links = %{$dbd->links};
|
||||
if (%links) {
|
||||
my @links = sort keys %links;
|
||||
|
||||
# Declare the link interfaces
|
||||
print $out wrap('epicsShareExtern jlif ', ' ',
|
||||
join(', ', map {"*pvar_jlif_$_"} @links)), ";\n\n";
|
||||
|
||||
# List of pointers to each link interface
|
||||
print $out "static struct jlif *jlifsl[] = {\n";
|
||||
print $out join(",\n", map {" pvar_jlif_$_"} @links);
|
||||
print $out "};\n\n";
|
||||
}
|
||||
|
||||
my @registrars = sort keys %{$dbd->registrars};
|
||||
my @functions = sort keys %{$dbd->functions};
|
||||
push @registrars, map {"register_func_$_"} @functions;
|
||||
@@ -234,6 +248,10 @@ print $out (<< 'END') if %drivers;
|
||||
registerDrivers(pbase, NELEMENTS(drvsl), driverSupportNames, drvsl);
|
||||
END
|
||||
|
||||
print $out (<< 'END') if %links;
|
||||
registerJLinks(pbase, NELEMENTS(jlifsl), jlifsl);
|
||||
END
|
||||
|
||||
print $out (<< "END") for @registrars;
|
||||
pvar_func_$_();
|
||||
END
|
||||
|
||||
Reference in New Issue
Block a user