From c0d4835e6699972c95a55bc11e9fa8b0ddeebb52 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 11 Dec 2017 23:45:35 -0600 Subject: [PATCH] lnkState: Add support for inverting the flag data Determine the truthiness of put data in its original data type. Adjust the link documentation to cover these changes. --- src/std/link/links.dbd.pod | 23 ++++++++---- src/std/link/lnkState.c | 72 +++++++++++++++++++++++++++++++------- 2 files changed, 76 insertions(+), 19 deletions(-) diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod index 07e1023f2..9b802b513 100644 --- a/src/std/link/links.dbd.pod +++ b/src/std/link/links.dbd.pod @@ -137,12 +137,18 @@ 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. +global flag as implemented by the dbState facility in C. The link +type can invert the sense of the dbState flag if desired. 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. +operation. When reading a flag, the value returned by the link will be zero or +one converted to the requested data type. When writing to a flag the boolean +value of the data written is determined in the originating data type. All +strings are regarded as true other than C<""> and C<"0"> which are both false. + +A link can be configured to invert the sense of the flag data by putting an +exclamation mark C before the first character of the flag's name in the link +address. 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 @@ -150,11 +156,14 @@ 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. +The link address must be a string providing the name of the dbState object, with +an optional leading C charater to indicate the flag's value should be +inverted. The dbState object will be created when the link is initialized if it +doesn't already exist. -=head4 Example +=head4 Examples {state:"redBeam"} + {state:"!simEnable"} =cut diff --git a/src/std/link/lnkState.c b/src/std/link/lnkState.c index b1f33a552..e24773727 100644 --- a/src/std/link/lnkState.c +++ b/src/std/link/lnkState.c @@ -40,7 +40,8 @@ typedef long (*FASTCONVERT)(); typedef struct state_link { jlink jlink; /* embedded object */ char *name; - int val; + short val; + short invert; dbStateId state; } state_link; @@ -58,6 +59,7 @@ static jlink* lnkState_alloc(short dbfType) slink->name = NULL; slink->state = NULL; + slink->invert = 0; slink->val = 0; IFDEBUG(10) @@ -84,6 +86,11 @@ static jlif_result lnkState_string(jlink *pjlink, const char *val, size_t len) IFDEBUG(10) printf("lnkState_string(state@%p, \"%.*s\")\n", slink, (int) len, val); + if (len > 1 && val[0] == '!') { + slink->invert = 1; + val++; len--; + } + slink->name = epicsStrnDup(val, len); return jlif_continue; } @@ -105,8 +112,8 @@ static void lnkState_report(const jlink *pjlink, int level, int indent) IFDEBUG(10) printf("lnkState_report(state@%p)\n", slink); - printf("%*s'state': \"%s\" = %d\n", indent, "", - slink->name, slink->val); + printf("%*s'state': \"%s\" = %s%s\n", indent, "", + slink->name, slink->invert ? "! " : "", slink->val ? "TRUE" : "FALSE"); } /*************************** lset Routines **************************/ @@ -155,7 +162,7 @@ static int lnkState_getDBFtype(const struct link *plink) IFDEBUG(10) printf("lnkState_getDBFtype(state@%p)\n", slink); - return DBF_LONG; + return DBF_SHORT; } static long lnkState_getElements(const struct link *plink, long *nelements) @@ -177,13 +184,15 @@ static long lnkState_getValue(struct link *plink, short dbrType, void *pbuffer, state_link *slink = CONTAINER(plink->value.json.jlink, struct state_link, jlink); long status; - FASTCONVERT conv = dbFastPutConvertRoutine[DBR_LONG][dbrType]; + short flag; + FASTCONVERT conv = dbFastPutConvertRoutine[DBR_SHORT][dbrType]; IFDEBUG(10) printf("lnkState_getValue(state@%p, %d, ...)\n", slink, dbrType); - slink->val = dbStateGet(slink->state); + flag = dbStateGet(slink->state); + slink->val = slink->invert ^ flag; status = conv(&slink->val, pbuffer, NULL); return status; @@ -194,20 +203,59 @@ static long lnkState_putValue(struct link *plink, short dbrType, { state_link *slink = CONTAINER(plink->value.json.jlink, struct state_link, jlink); - long status; - FASTCONVERT conv = dbFastPutConvertRoutine[dbrType][DBR_LONG]; + short val; + const char *pstr; IFDEBUG(10) - printf("lnkState_getValue(state@%p, %d, ...)\n", + printf("lnkState_putValue(state@%p, %d, ...)\n", slink, dbrType); if (nRequest == 0) return 0; - status = conv(pbuffer, &slink->val, NULL); - (slink->val ? dbStateSet : dbStateClear)(slink->state); + switch(dbrType) { + case DBR_CHAR: + case DBR_UCHAR: + val = !! *(const epicsInt8 *) pbuffer; + break; - return status; + case DBR_SHORT: + case DBR_USHORT: + val = !! *(const epicsInt16 *) pbuffer; + break; + + case DBR_LONG: + case DBR_ULONG: + val = !! *(const epicsInt32 *) pbuffer; + break; + + case DBR_INT64: + case DBR_UINT64: + val = !! *(const epicsInt64 *) pbuffer; + break; + + case DBR_FLOAT: + val = !! *(const epicsFloat32 *) pbuffer; + break; + + case DBR_DOUBLE: + val = !! *(const epicsFloat64 *) pbuffer; + break; + + case DBR_STRING: /* Only "" and "0" are FALSE */ + pstr = (const char *) pbuffer; + val = (pstr[0] != 0) && ((pstr[0] != '0') || (pstr[1] != 0)); + break; + + default: + return S_db_badDbrtype; + } + slink->val = val; + + val ^= slink->invert; + (val ? dbStateSet : dbStateClear)(slink->state); + + return 0; } /************************* Interface Tables *************************/