Skip to content

Commit

Permalink
Merge e867b0a into 66ff5a7
Browse files Browse the repository at this point in the history
  • Loading branch information
mdavidsaver committed Oct 5, 2021
2 parents 66ff5a7 + e867b0a commit faecda0
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 91 deletions.
133 changes: 64 additions & 69 deletions modules/database/src/std/rec/mbboDirectRecord.c
Expand Up @@ -88,6 +88,14 @@ static long writeValue(mbboDirectRecord *);

#define NUM_BITS 32

static
void bitsFromVAL(mbboDirectRecord *prec)
{
unsigned i;
for(i=0; i<NUM_BITS; i++)
(&prec->b0)[i] = !!(prec->val&(1u<<i));
}

static long init_record(struct dbCommon *pcommon, int pass)
{
struct mbboDirectRecord *prec = (struct mbboDirectRecord *)pcommon;
Expand Down Expand Up @@ -131,16 +139,21 @@ static long init_record(struct dbCommon *pcommon, int pass)
status = 0;
}

if (!prec->udf &&
prec->omsl == menuOmslsupervisory) {
/* Set initial B0 - B1F from VAL */
epicsUInt32 val = prec->val;
if (!prec->udf)
bitsFromVAL(prec);
else {
/* Did user set any of the B0-B1F fields? */
epicsUInt8 *pBn = &prec->b0;
epicsUInt32 val = 0, bit = 1;
int i;

for (i = 0; i < NUM_BITS; i++) {
*pBn++ = !! (val & 1);
val >>= 1;
for (i = 0; i < NUM_BITS; i++, bit <<= 1)
if (*pBn++)
val |= bit;

if (val) { /* Yes! */
prec->val = val;
prec->udf = FALSE;
}
}

Expand Down Expand Up @@ -174,24 +187,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);

Expand Down Expand Up @@ -234,6 +236,9 @@ static long process(struct dbCommon *pcommon)
recGblGetTimeStampSimm(prec, prec->simm, NULL);
}

/* update bits to reflect any change made by dset */
bitsFromVAL(prec);

monitor(prec);

/* Wrap up */
Expand All @@ -255,60 +260,37 @@ 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;

for (i = 0; i < NUM_BITS; i++, bit <<= 1)
if (*pBn++)
val |= bit;
prec->val = val;
} 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);

/* 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;

for (i = 0; i < NUM_BITS; i++, pBn++, val >>= 1) {
epicsUInt8 oBn = *pBn;

*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;
convert(prec);
}

prec->udf = FALSE;
return 0;
}

Expand All @@ -330,8 +312,21 @@ static void monitor(mbboDirectRecord *prec)
events |= DBE_VALUE | DBE_LOG;
prec->mlst = prec->val;
}
if (events)
if (events) {
db_post_events(prec, &prec->val, events);
}
{
unsigned i;
epicsUInt32 bitsChanged = prec->obit ^ (epicsUInt32)prec->val;

for(i=0; i<NUM_BITS; i++) {
/* post bit when value or alarm severity changes */
if((events&~(DBE_VALUE|DBE_LOG)) || (bitsChanged&(1u<<i))) {
db_post_events(prec, (&prec->b0)+i, events | DBE_VALUE | DBE_LOG);
}
}
prec->obit = prec->val;
}

events |= DBE_VALUE | DBE_LOG;
if (prec->oraw != prec->rval) {
Expand Down
79 changes: 57 additions & 22 deletions modules/database/src/std/rec/mbboDirectRecord.dbd.pod
Expand Up @@ -9,11 +9,14 @@

=title Multi-Bit Binary Output Direct Record (mbboDirect)

The mbboDirect record performs the opposite function to that of the mbbiDirect
record. It accumulates bits (in the fields B0 - BF) as unsigned characters, and
converts them to a word which is then written out to hardware. If a bit field is
non-zero, it is interpreted as a binary 1. On the other hand, if it is zero, it
is interpreted as a binary 0.
The mbboDirect record performs roughly the opposite function to that of the
L<mbbiDirect record|mbbiDirectRecord>.

It can accept boolean values in its 32 bit fields (B0-B9, BA-BF, B10-B19 and
B1A-B1F), and converts them to a 32-bit signed integer in VAL which is provided
to the device support. A zero value in a bit field becomes a zero bit in VAL, a
non-zero value in a bit field becomes a one bit in VAL, with B0 being the least
signficant bit and B1F the MSB/sign bit.

=recordtype mbboDirect

Expand All @@ -33,24 +36,51 @@ These fields are listed in L<Scan Fields|dbCommonRecord/Scan Fields>.

=head3 Desired Output Parameters

The mbboDirect record, like all output records, must specify where its output
originates. The output mode select field (OMSL) determines whether the output
originates from another record or from database access. When set to C<<<
closed_loop >>>, the desired output is retrieved from the link specified in the
desired output (DOL) field--which can specify either a database or channel
access link--and placed into the VAL field. When set to C<<< supervisory >>>,
the DOL field is ignored and the current value of VAL is used. The desired
output can be written into the VAL field via dpPuts at run-time when the record
is in C<<< supervisory >>> mode. DOL can also be a constant, in which case VAL
is initialized to the constant value. Note that OMSL cannot be C<<< closed_loop
>>> when DOL is a constant.

VAL is then converted to RVAL in the routine described in the next section.
However, the C<<< Soft Channel >>> device support module for the mbboDirect
record writes the VAL field's value without any conversion.
Like all output records, the mbboDirect record must specify where its output
should originate when it gets processed. The Output Mode SeLect field (OMSL)
determines whether the output value should be read from another record or not.
When set to C<<< closed_loop >>>, a 32-bit integer value (the "desired output")
will be read from a link specified in the Desired Output Link (DOL) field and
placed into the VAL field.

When OMSL is set to C<<< supervisory >>>, the DOL field is ignored during
processing and the contents of VAL are used. A value to be output may thus be
written direcly into the VAL field from elsewhere as long as the record is in
C<<< supervisory >>> mode.

=fields OMSL, DOL, VAL

=head4 Bit Fields

The fields B0 through BF and B10 through B1F provide an alternative way to set
the individual bits of the VAL field when the record is in C<<< supervisory >>>
mode. Writing to one of these fields will then modify the corresponding bit in
VAL, and writing to VAL will update these bit fields from that value.

The VAL field is signed so it can be accessed through Channel Access as an
integer; if it were made unsigned (a C<DBF_ULONG>) its representation through
Channel Access would become a C<double>, which could cause problems with some
client programs.

Prior to the EPICS 7.0.6.1 release the individual bit fields were not updated
while the record was in C<<< closed_loop >>> mode with VAL being set from the
DOL link, and writing to the bit fields in that mode could cause the record to
process but the actual field values would not affect VAL at all. Changing the
OMSL field from C<<< closed_loop >>> to C<<< supervisory >>> would set the bit
fields from VAL at that time and trigger a monitor event for the bits that
changed at that time. At record initialization if VAL is defined and the OMSL
field is C<<< supervisory >>> the bit fields would be set from VAL.

From EPICS 7.0.6.1 the bit fields get updated from VAL during record processing
and monitors are triggered on them in either mode. Attempts to write to the bit
fields while in C<<< closed_loop >>> mode will be rejected by the C<special()>
routine which may trigger an error from the client that wrote to them. During
initialization if the record is still undefined (UDF) after DOL has been read
and the device support initialized but at least one of the B0-B1F fields is
non-zero, the VAL field will be set from those fields and UDF will be cleared.

=fields B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF, B10, B11, B12, B13, B14, B15, B16, B17, B18, B19, B1A, B1B, B1C, B1D, B1E, B1F

=head3 Convert and Write Parameters

For records that are to write values to hardware devices, the OUT output link
Expand Down Expand Up @@ -104,7 +134,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)
Expand Down Expand Up @@ -154,6 +183,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")
Expand All @@ -169,8 +203,9 @@ 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 a similar role for bits held in the B0-B1F fields.

=fields NOBT, ORAW, MASK, MLST
=fields NOBT, ORAW, MASK, MLST, OBIT

=head3 Simulation Mode Parameters

Expand Down

0 comments on commit faecda0

Please sign in to comment.