diff --git a/modules/database/src/std/rec/mbboDirectRecord.c b/modules/database/src/std/rec/mbboDirectRecord.c index 7c5ba294c..49ecf740e 100644 --- a/modules/database/src/std/rec/mbboDirectRecord.c +++ b/modules/database/src/std/rec/mbboDirectRecord.c @@ -88,6 +88,14 @@ static long writeValue(mbboDirectRecord *); #define NUM_BITS 32 +static +void bitsFromVAL(mbboDirectRecord *prec) +{ + unsigned i; + for(i=0; ib0)[i] = !!(prec->val&(1u<udf && - prec->omsl == menuOmslsupervisory) { - /* Set initial B0 - B1F from VAL */ - epicsUInt32 val = prec->val; - epicsUInt8 *pBn = &prec->b0; - int i; - - for (i = 0; i < NUM_BITS; i++) { - *pBn++ = !! (val & 1); - val >>= 1; - } - } - + bitsFromVAL(prec); prec->mlst = prec->val; prec->oraw = prec->rval; prec->orbv = prec->rbv; @@ -174,24 +170,13 @@ static long process(struct dbCommon *pcommon) } prec->val = val; } - else if (prec->omsl == menuOmslsupervisory) { - epicsUInt8 *pBn = &prec->b0; - epicsUInt32 val = 0; - epicsUInt32 bit = 1; - int i; - - /* Construct VAL from B0 - B1F */ - for (i = 0; i < NUM_BITS; i++, bit <<= 1) - if (*pBn++) - val |= bit; - prec->val = val; - } else if (prec->udf) { - recGblSetSevr(prec, UDF_ALARM, prec->udfs); + recGblSetSevrMsg(prec, UDF_ALARM, prec->udfs, "UDFS"); goto CONTINUE; } prec->udf = FALSE; + bitsFromVAL(prec); /* Convert VAL to RVAL */ convert(prec); @@ -234,6 +219,9 @@ CONTINUE: recGblGetTimeStampSimm(prec, prec->simm, NULL); } + /* update bits to reflect any change made by dset */ + bitsFromVAL(prec); + monitor(prec); /* Wrap up */ @@ -255,60 +243,41 @@ static long special(DBADDR *paddr, int after) return 0; } - if (!after) - return 0; - - switch (paddr->special) { - case SPC_MOD: /* Bn field modified */ - if (prec->omsl == menuOmslsupervisory) { - /* Adjust VAL corresponding to the bit changed */ - epicsUInt8 *pBn = (epicsUInt8 *) paddr->pfield; - epicsUInt32 bit = 1 << (pBn - &prec->b0); - - if (*pBn) - prec->val |= bit; - else - prec->val &= ~bit; - - prec->udf = FALSE; - convert(prec); + if(after==0 && fieldIndex >= mbboDirectRecordB0 && fieldIndex <= mbboDirectRecordB1F) { + if(prec->omsl == menuOmslclosed_loop) { + /* To avoid confusion, reject changes to bit fields while in closed loop. + * Not a 100% solution as confusion can still arise if dset overwrites VAL. + */ + return S_db_noMod; } - break; - case SPC_RESET: /* OMSL field modified */ - if (prec->omsl == menuOmslclosed_loop) { - /* Construct VAL from B0 - B1F */ - epicsUInt8 *pBn = &prec->b0; - epicsUInt32 val = 0, bit = 1; - int i; + } else if(after==1 && fieldIndex >= mbboDirectRecordB0 && fieldIndex <= mbboDirectRecordB1F) { + /* Adjust VAL corresponding to the bit changed */ + epicsUInt8 *pBn = (epicsUInt8 *) paddr->pfield; + epicsUInt32 bit = 1 << (pBn - &prec->b0); + epicsUInt32 oobit = prec->obit; - for (i = 0; i < NUM_BITS; i++, bit <<= 1) - if (*pBn++) - val |= bit; - prec->val = val; + /* Because this is !(VAL and PP), dbPut() will always post a monitor on this B* field + * after we return. We must keep track of this change separately from MLST to handle + * situations where VAL and B* are changed prior to next monitor(). eg. by dset to + * reflect bits actually written. This is the role of OBIT. + */ + + if (*pBn) { + prec->val |= bit; + prec->obit |= bit; + } else { + prec->val &= ~bit; + prec->obit &= ~bit; } - else if (prec->omsl == menuOmslsupervisory) { - /* Set B0 - B1F from VAL and post monitors */ - epicsUInt32 val = prec->val; - epicsUInt8 *pBn = &prec->b0; - int i; + if(oobit!=prec->obit) + db_post_events(prec, &prec->obit, DBE_VALUE|DBE_LOG); - for (i = 0; i < NUM_BITS; i++, pBn++, val >>= 1) { - epicsUInt8 oBn = *pBn; + prec->udf = FALSE; + convert(prec); - *pBn = !! (val & 1); - if (oBn != *pBn) - db_post_events(prec, pBn, DBE_VALUE | DBE_LOG); - } - } - break; - - default: - recGblDbaddrError(S_db_badChoice, paddr, "mbboDirect: special"); - return S_db_badChoice; } - prec->udf = FALSE; return 0; } @@ -329,9 +298,24 @@ static void monitor(mbboDirectRecord *prec) if (prec->mlst != prec->val) { events |= DBE_VALUE | DBE_LOG; prec->mlst = prec->val; + db_post_events(prec, &prec->mlst, events); } - if (events) + if (events) { db_post_events(prec, &prec->val, events); + } + { + unsigned i; + epicsUInt32 bitsChanged = prec->obit ^ (epicsUInt32)prec->val; + + for(i=0; ib0)+i, events | DBE_VALUE | DBE_LOG); + } + } + prec->obit = prec->val; + db_post_events(prec, &prec->obit, events); + } events |= DBE_VALUE | DBE_LOG; if (prec->oraw != prec->rval) { diff --git a/modules/database/src/std/rec/mbboDirectRecord.dbd.pod b/modules/database/src/std/rec/mbboDirectRecord.dbd.pod index 649e752c8..7dedc8eec 100644 --- a/modules/database/src/std/rec/mbboDirectRecord.dbd.pod +++ b/modules/database/src/std/rec/mbboDirectRecord.dbd.pod @@ -104,7 +104,6 @@ Parameters> for more on the record name (NAME) and description (DESC) fields. field(OMSL,DBF_MENU) { prompt("Output Mode Select") promptgroup("50 - Output") - special(SPC_RESET) pp(TRUE) interest(1) menu(menuOmsl) @@ -154,6 +153,11 @@ Parameters> for more on the record name (NAME) and description (DESC) fields. special(SPC_NOMOD) interest(3) } + field(OBIT,DBF_LONG) { + prompt("Last Bit mask Monitored") + special(SPC_NOMOD) + interest(3) + } field(SHFT,DBF_USHORT) { prompt("Shift") promptgroup("50 - Output") @@ -169,6 +173,7 @@ MASK is used by device support routine to read the hardware register. Record support sets low order NOBT bits. Device support can shift this value. MLST holds the value when the last monitor for value change was triggered. +OBIT has similar role wrt. the B* fields. =fields NOBT, ORAW, MASK, MLST