diff --git a/src/std/link/Makefile b/src/std/link/Makefile index 31d14b825..5ad9777a8 100644 --- a/src/std/link/Makefile +++ b/src/std/link/Makefile @@ -2,7 +2,7 @@ # Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne # National Laboratory. # EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. +# in file LICENSE that is included with this distribution. #************************************************************************* # This is a Makefile fragment, see src/std/Makefile. @@ -13,6 +13,6 @@ DBD += links.dbd dbRecStd_SRCS += lnkConst.c dbRecStd_SRCS += lnkCalc.c +dbRecStd_SRCS += lnkState.c HTMLS += links.html - diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod index d94e9e8f0..07e1023f2 100644 --- a/src/std/link/links.dbd.pod +++ b/src/std/link/links.dbd.pod @@ -13,6 +13,8 @@ The following additional link types are available in this release: =item * L +=item * L + =back =head2 Using JSON Links @@ -129,3 +131,30 @@ atomically with the value of the input argument. {calc: {expr:"A*B", args:[{db:"record.VAL"}, 1.5], prec:3}} =cut + +link(state, lnkStateIf) + +=head3 dbState Link C<"state"> + +A dbState link is one that reads or writes a boolean value from/to a named +global flag as implemented by the dbState facility in C. + +The value of the named flag is read or written at the time of the link I/O +operation. The boolean flag data is represented as a C that can only +hold the values zero or one; putting any non-zero numeric value to a link sets +the boolean flag value, putting a zero value clears it. + +These dbState flags can be accessed from the IOC Shell with various dbState +commands, and are also used by the C<"sync"> Channel-Access server-side filter +mechanism. + +=head4 Parameters + +The link address must be a string providing the name of the dbState object, +which will be created when the link is initialized if it doesn't already exist. + +=head4 Example + + {state:"redBeam"} + +=cut diff --git a/src/std/link/lnkState.c b/src/std/link/lnkState.c new file mode 100644 index 000000000..b1f33a552 --- /dev/null +++ b/src/std/link/lnkState.c @@ -0,0 +1,236 @@ +/*************************************************************************\ +* Copyright (c) 2017 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* lnkState.c */ + +/* Usage: + * {state:green} + */ + +#include +#include +#include +#include + +#include "alarm.h" +#include "dbDefs.h" +#include "errlog.h" +#include "epicsAssert.h" +#include "epicsString.h" +#include "epicsTypes.h" +#include "dbAccessDefs.h" +#include "dbCommon.h" +#include "dbConvertFast.h" +#include "dbLink.h" +#include "dbJLink.h" +#include "dbStaticLib.h" +#include "dbStaticPvt.h" +#include "dbState.h" +#include "recGbl.h" +#include "epicsExport.h" + + +typedef long (*FASTCONVERT)(); + +#define IFDEBUG(n) if(slink->jlink.debug) + +typedef struct state_link { + jlink jlink; /* embedded object */ + char *name; + int val; + dbStateId state; +} state_link; + +static lset lnkState_lset; + + +/*************************** jlif Routines **************************/ + +static jlink* lnkState_alloc(short dbfType) +{ + state_link *slink = calloc(1, sizeof(struct state_link)); + + IFDEBUG(10) + printf("lnkState_alloc()\n"); + + slink->name = NULL; + slink->state = NULL; + slink->val = 0; + + IFDEBUG(10) + printf("lnkState_alloc -> state@%p\n", slink); + + return &slink->jlink; +} + +static void lnkState_free(jlink *pjlink) +{ + state_link *slink = CONTAINER(pjlink, struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_free(state@%p)\n", slink); + + free(slink->name); + free(slink); +} + +static jlif_result lnkState_string(jlink *pjlink, const char *val, size_t len) +{ + state_link *slink = CONTAINER(pjlink, struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_string(state@%p, \"%.*s\")\n", slink, (int) len, val); + + slink->name = epicsStrnDup(val, len); + return jlif_continue; +} + +static struct lset* lnkState_get_lset(const jlink *pjlink) +{ + state_link *slink = CONTAINER(pjlink, struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_get_lset(state@%p)\n", pjlink); + + return &lnkState_lset; +} + +static void lnkState_report(const jlink *pjlink, int level, int indent) +{ + state_link *slink = CONTAINER(pjlink, struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_report(state@%p)\n", slink); + + printf("%*s'state': \"%s\" = %d\n", indent, "", + slink->name, slink->val); +} + +/*************************** lset Routines **************************/ + +static void lnkState_open(struct link *plink) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_open(state@%p)\n", slink); + + slink->state = dbStateCreate(slink->name); +} + +static void lnkState_remove(struct dbLocker *locker, struct link *plink) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_remove(state@%p)\n", slink); + + free(slink->name); + free(slink); + + plink->value.json.jlink = NULL; +} + +static int lnkState_isConn(const struct link *plink) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_isConn(state@%p)\n", slink); + + return !! slink->state; +} + +static int lnkState_getDBFtype(const struct link *plink) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_getDBFtype(state@%p)\n", slink); + + return DBF_LONG; +} + +static long lnkState_getElements(const struct link *plink, long *nelements) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_getElements(state@%p, (%ld))\n", + slink, *nelements); + + *nelements = 1; + return 0; +} + +static long lnkState_getValue(struct link *plink, short dbrType, void *pbuffer, + long *pnRequest) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + long status; + FASTCONVERT conv = dbFastPutConvertRoutine[DBR_LONG][dbrType]; + + IFDEBUG(10) + printf("lnkState_getValue(state@%p, %d, ...)\n", + slink, dbrType); + + slink->val = dbStateGet(slink->state); + status = conv(&slink->val, pbuffer, NULL); + + return status; +} + +static long lnkState_putValue(struct link *plink, short dbrType, + const void *pbuffer, long nRequest) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + long status; + FASTCONVERT conv = dbFastPutConvertRoutine[dbrType][DBR_LONG]; + + IFDEBUG(10) + printf("lnkState_getValue(state@%p, %d, ...)\n", + slink, dbrType); + + if (nRequest == 0) + return 0; + + status = conv(pbuffer, &slink->val, NULL); + (slink->val ? dbStateSet : dbStateClear)(slink->state); + + return status; +} + +/************************* Interface Tables *************************/ + +static lset lnkState_lset = { + 0, 1, /* not Constant, Volatile */ + lnkState_open, lnkState_remove, + NULL, NULL, NULL, + lnkState_isConn, lnkState_getDBFtype, lnkState_getElements, + lnkState_getValue, + NULL, NULL, NULL, + NULL, NULL, + NULL, NULL, + lnkState_putValue, NULL, + NULL, NULL +}; + +static jlif lnkStateIf = { + "state", lnkState_alloc, lnkState_free, + NULL, NULL, NULL, NULL, lnkState_string, + NULL, NULL, NULL, + NULL, NULL, + NULL, lnkState_get_lset, + lnkState_report, NULL +}; +epicsExportAddress(jlif, lnkStateIf);