Hi:
I have an mbboDirect that writes to hardware, with each B0, B1, .. bit shown on a display as a checkbox for users to set/clear.
At startup, the record is INVALID, VAL and all B0, B1, .. bit fields defaulting to 0, until device support can once communicate with the hardware and fetch the initial value, i.e., the record correctly initializes from the hardware for 'bumpless' startup.
On the GUI, however, this looks odd because the mbboDirect doesn't send out monitors for the alarm change if the bit field value is still zero. Only bit fields that changed to 1 as a result of the 'bumpless' initialization at startup get updates.
So on the GUI, all those checkboxes with values 0 show an INVALID alarm until the display is closed/re-opened.
The effect can be duplicated with a softIoc running just this:
record(mbboDirect, "test")
{
field(SCAN, "10 second")
}
Start the IOC, then quickly run `camonitor test test.B0 test.B1`.
Initially, they read
test <undefined> 0 UDF INVALID
test.B0 <undefined> 0 UDF INVALID
test.B1 <undefined> 0 UDF INVALID
After about 10 seconds when the record is first scanned, there is one update:
test 2021-08-31 12:54:08.266960 0
There is no monitor for the B0, B1, ... bit fields. When closing the monitor and starting it again, all fields read OK.
I see that behavior with at least base 3.15.9, R7.0.4.1 and 7.0.6.
One way to fix it is to update mbboDirectRecord.c monitor() as shown below, where the "if (events) .." block now sends out monitors on all bit fields. With that in place, the camonitor will see
a time stamp and no alarm as soon as the record processes on all bit fields.
Were these
db_post_events simply missing?
Thanks,
Kay
static void monitor(mbboDirectRecord *prec)
{
epicsUInt16 events = recGblResetAlarms(prec);
if (prec->mlst != prec->val) {
events |= DBE_VALUE | DBE_LOG;
prec->mlst = prec->val;
}
if (events)
{
db_post_events(prec, &prec->val, events);
// Update bit fields
epicsUInt8 *pBn = &prec->b0;
int i;
for (i = 0; i < NUM_BITS; i++, pBn++)
db_post_events(prec, pBn, events);
}
events |= DBE_VALUE | DBE_LOG;
if (prec->oraw != prec->rval) {
db_post_events(prec, &prec->rval, events);
prec->oraw = prec->rval;
}
if (prec->orbv != prec->rbv) {
db_post_events(prec, &prec->rbv, events);
prec->orbv = prec->rbv;
}
}