rec: mbbiDirect and mbboDirect refactoring

This includes changes to functionality, documented.
This commit is contained in:
Andrew Johnson
2012-12-11 18:25:01 -06:00
parent 475fc8e122
commit 04ff9eb8a1
7 changed files with 523 additions and 576 deletions

View File

@@ -15,6 +15,38 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.</p>
<h2 align="center">Changes between 3.15.0.1 and 3.15.0.2</h2>
<!-- Insert new items immediately below here ... -->
<h3>mbboDirect and mbbiDirect records</h3>
<p>These record types have undergone some significant rework, and will behave
slightly differently than they did in their 3.14 versions. The externally
visible changes are as follows:</p>
<h5>mbbiDirect</h5>
<ul>
<li>If the MASK field is set in a database file, it will not be over-written
when the record is initialized. This allows non-contiguous masks to be set,
although only the device support actually uses the MASK field.</li>
<li>If process() finds the UDF field to be set, the record will raise a
UDF/INVALID alarm.</li>
</ul>
<h5>mbboDirect</h5>
<ul>
<li>If the MASK field is set in a database file, it will not be over-written
when the record is initialized. This allows non-contiguous masks to be set,
although only the device support actually uses the MASK field.</li>
<li>After the device support's init_record() routine returns during record
initialization, if OMSL is <q>supervisory</q> and UDF is clear the fields
B0-BF will be set from the current VAL field.</li>
<li>When a put to the OMSL field sets it to <q>supervisory</q>, the fields
B0-BF will be set from the current VAL field. This did not used to happen,
the individual bit fields were previously never modified by the record.
Note that this change may require some databases to be modified, if they
were designed to take advantage of the previous behavior.</li>
</ul>
<h3>Redirection of the errlog console stream</h3>
<p>A new routine has been added to the errlog facility which allows the console

View File

@@ -1,64 +1,36 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* devMbboDirectSoft.c */
/* base/src/dev $Revision-Id$ */
/*
* Original Author: Bob Dalesio
* Current Author: Matthew Needes
* Date: 10-08-93
* Original Author: Bob Dalesio
* Date: 10-08-93
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "dbDefs.h"
#include <stdio.h>
#include "dbAccess.h"
#include "recGbl.h"
#include "recSup.h"
#include "devSup.h"
#include "mbboDirectRecord.h"
#include "epicsExport.h"
/* Create the dset for devMbboSoft */
static long init_record(mbboDirectRecord *prec);
static long write_mbbo(mbboDirectRecord *prec);
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN write_mbbo;
}devMbboDirectSoft={
5,
NULL,
NULL,
init_record,
NULL,
write_mbbo
};
epicsExportAddress(dset,devMbboDirectSoft);
static long init_record(mbboDirectRecord *prec)
{
long status = 0;
/* dont convert */
status = 2;
return status;
} /* end init_record() */
static long write_mbbo(mbboDirectRecord *prec)
{
dbPutLink(&prec->out,DBR_USHORT,&prec->val,1);
dbPutLink(&prec->out, DBR_USHORT, &prec->val, 1);
return 0;
}
/* Create the dset for devMbboDirectSoft */
struct {
dset common;
DEVSUPFUN write;
} devMbboDirectSoft = {
{5, NULL, NULL, NULL, NULL},
write_mbbo
};
epicsExportAddress(dset, devMbboDirectSoft);

View File

@@ -1,66 +1,56 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* devMbboDirectSoftCallback.c */
/*
* Author: Marty Kraimer
* Date: 04NOV2003
* Original Author: Marty Kraimer
* Date: 04NOV2003
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "recGbl.h"
#include "recSup.h"
#include "devSup.h"
#include "mbboDirectRecord.h"
#include "epicsExport.h"
/* Create the dset for devMbboSoft */
static long write_mbbo(mbboDirectRecord *prec);
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN write_mbbo;
}devMbboDirectSoftCallback={
5,
NULL,
NULL,
NULL,
NULL,
write_mbbo
};
epicsExportAddress(dset,devMbboDirectSoftCallback);
static long write_mbbo(mbboDirectRecord *prec)
static long write_mbbo(mbboDirectRecord *prec)
{
struct link *plink = &prec->out;
long status;
if(prec->pact) return(0);
if(plink->type!=CA_LINK) {
status = dbPutLink(plink,DBR_USHORT,&prec->val,1);
return(status);
if (prec->pact)
return 0;
if (plink->type != CA_LINK) {
status = dbPutLink(plink, DBR_USHORT, &prec->val, 1);
return status;
}
status = dbCaPutLinkCallback(plink,DBR_USHORT,&prec->val,1,
dbCaCallbackProcess,plink);
if(status) {
recGblSetSevr(prec,LINK_ALARM,INVALID_ALARM);
return(status);
status = dbCaPutLinkCallback(plink, DBR_USHORT, &prec->val, 1,
dbCaCallbackProcess, plink);
if (status) {
recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
return status;
}
prec->pact = TRUE;
return(0);
return 0;
}
/* Create the dset for devMbboSoft */
struct {
dset common;
DEVSUPFUN write;
} devMbboDirectSoftCallback = {
{5, NULL, NULL, NULL, NULL},
write_mbbo
};
epicsExportAddress(dset, devMbboDirectSoftCallback);

View File

@@ -1,70 +1,50 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* devMbboDirectSoftRaw.c */
/* base/src/dev $Revision-Id$ */
/*
* Author: Janet Anderson
* Current Author: Matthew Needes
* Date: 10-08-93
* Original Author: Janet Anderson
* Date: 10-08-93
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "dbDefs.h"
#include <stdio.h>
#include "dbAccess.h"
#include "recGbl.h"
#include "recSup.h"
#include "epicsTypes.h"
#include "devSup.h"
#include "mbboDirectRecord.h"
#include "epicsExport.h"
/* Create the dset for devMbboDirectSoftRaw */
static long init_record(mbboDirectRecord *prec);
static long write_mbbo(mbboDirectRecord *prec);
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN write_mbbo;
}devMbboDirectSoftRaw={
5,
NULL,
NULL,
init_record,
NULL,
write_mbbo
};
epicsExportAddress(dset,devMbboDirectSoftRaw);
static long init_record(mbboDirectRecord *prec)
{
long status = 0;
if (prec->out.type != PV_LINK)
status = 2;
/*to preserve old functionality*/
if(prec->nobt == 0) prec->mask = 0xffffffff;
if (prec->nobt == 0)
prec->mask = 0xffffffff;
prec->mask <<= prec->shft;
return status;
} /* end init_record() */
return 2; /* Don't convert */
}
static long write_mbbo(mbboDirectRecord *prec)
{
unsigned long data;
epicsUInt32 data;
data = prec->rval & prec->mask;
dbPutLink(&prec->out,DBR_LONG, &data,1);
dbPutLink(&prec->out, DBR_ULONG, &data, 1);
return 0;
}
/* Create the dset for devMbboDirectSoftRaw */
struct {
dset common;
DEVSUPFUN write;
} devMbboDirectSoftRaw = {
{5, NULL, NULL, init_record, NULL},
write_mbbo
};
epicsExportAddress(dset, devMbboDirectSoftRaw);

View File

@@ -1,66 +1,50 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* devMbboSoftRaw.c */
/* base/src/dev $Revision-Id$ */
/*
* Author: Janet Anderson
* Date: 3-28-92
* Original Author: Janet Anderson
* Date: 3-28-92
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "dbDefs.h"
#include <stdio.h>
#include "dbAccess.h"
#include "recGbl.h"
#include "recSup.h"
#include "epicsTypes.h"
#include "devSup.h"
#include "mbboRecord.h"
#include "epicsExport.h"
/* Create the dset for devMbboSoftRaw */
static long init_record(mbboRecord *prec);
static long write_mbbo(mbboRecord *prec);
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN write_mbbo;
}devMbboSoftRaw={
5,
NULL,
NULL,
init_record,
NULL,
write_mbbo
};
epicsExportAddress(dset,devMbboSoftRaw);
static long init_record(mbboRecord *prec)
{
/*to preserve old functionality*/
if (prec->nobt == 0) prec->mask = 0xffffffff;
if (prec->nobt == 0)
prec->mask = 0xffffffff;
prec->mask <<= prec->shft;
/*dont convert*/
return 2;
} /* end init_record() */
return 2; /* Don't convert */
}
static long write_mbbo(mbboRecord *prec)
{
unsigned long data;
epicsUInt32 data;
data = prec->rval & prec->mask;
dbPutLink(&prec->out,DBR_LONG, &data,1);
dbPutLink(&prec->out, DBR_ULONG, &data, 1);
return 0;
}
/* Create the dset for devMbboSoftRaw */
struct {
dset common;
DEVSUPFUN write;
} devMbboSoftRaw = {
{5, NULL, NULL, init_record, NULL},
write_mbbo
};
epicsExportAddress(dset, devMbboSoftRaw);

View File

@@ -1,5 +1,5 @@
/*************************************************************************\
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
@@ -11,9 +11,10 @@
/* $Revision-Id$ */
/* recMbbiDirect.c - Record Support routines for mbboDirect records */
/* mbbiDirectRecord.c - Record Support routines for mbboDirect records */
/*
* Original Author: Bob Dalesio and Matthew Needes 10-07-93
* Original Authors: Bob Dalesio and Matthew Needes
* Date: 10-07-93
*/
#include <stddef.h>
@@ -23,7 +24,7 @@
#include <string.h>
#include "dbDefs.h"
#include "epicsPrint.h"
#include "errlog.h"
#include "alarm.h"
#include "dbAccess.h"
#include "dbEvent.h"
@@ -59,219 +60,203 @@ static long process(mbbiDirectRecord *);
#define get_alarm_double NULL
rset mbbiDirectRSET={
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_control_double,
get_alarm_double
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_control_double,
get_alarm_double
};
epicsExportAddress(rset,mbbiDirectRSET);
struct mbbidset { /* multi bit binary input dset */
long number;
DEVSUPFUN dev_report;
DEVSUPFUN init;
DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_mbbi;/*(0,2)=>(success, success no convert)*/
long number;
DEVSUPFUN dev_report;
DEVSUPFUN init;
DEVSUPFUN init_record; /*returns: (-1,0)=>(failure, success)*/
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_mbbi; /*returns: (0,2)=>(success, success no convert)*/
};
static void refresh_bits(mbbiDirectRecord *, unsigned short);
static void monitor(mbbiDirectRecord *);
static long readValue(mbbiDirectRecord *);
#define NUM_BITS 16
/* refreshes all the bit fields based on a hardware value
and sends monitors if the bit's value or the record's
severity/status have changed */
static void refresh_bits(mbbiDirectRecord *prec,
unsigned short monitor_mask)
{
unsigned short i;
unsigned short mask = 1;
unsigned short momask;
unsigned char *bit;
bit = &(prec->b0);
for (i=0; i<NUM_BITS; i++, mask = mask << 1, bit++) {
momask = monitor_mask;
if (prec->val & mask) {
if (*bit == 0) {
*bit = 1;
momask |= DBE_VALUE | DBE_LOG;
}
} else {
if (*bit != 0) {
*bit = 0;
momask |= DBE_VALUE | DBE_LOG;
}
}
if (momask)
db_post_events(prec,bit,momask);
}
}
#define NUM_BITS 16
static long init_record(mbbiDirectRecord *prec, int pass)
{
struct mbbidset *pdset;
long status;
struct mbbidset *pdset = (struct mbbidset *) prec->dset;
long status = 0;
if (pass==0) return(0);
if (pass == 0)
return status;
/* siml must be a CONSTANT or a PV_LINK or a DB_LINK or a CA_LINK*/
if (prec->siml.type == CONSTANT) {
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
if (!pdset) {
recGblRecordError(S_dev_noDSET, prec, "mbbiDirect: init_record");
return S_dev_noDSET;
}
/* siol must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siol.type == CONSTANT) {
recGblInitConstantLink(&prec->siol,DBF_USHORT,&prec->sval);
if ((pdset->number < 5) || (pdset->read_mbbi == NULL)) {
recGblRecordError(S_dev_missingSup, prec, "mbbiDirect: init_record");
return S_dev_missingSup;
}
if(!(pdset = (struct mbbidset *)(prec->dset))) {
recGblRecordError(S_dev_noDSET,(void *)prec,"mbbiDirect: init_record");
return(S_dev_noDSET);
}
/* must have read_mbbi function defined */
if( (pdset->number < 5) || (pdset->read_mbbi == NULL) ) {
recGblRecordError(S_dev_missingSup,(void *)prec,"mbbiDirect: init_record");
return(S_dev_missingSup);
}
/* initialize mask*/
prec->mask = (1 << prec->nobt) - 1;
if (prec->siml.type == CONSTANT)
recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
if( pdset->init_record ) {
if((status=(*pdset->init_record)(prec))) return(status);
refresh_bits(prec, 0);
if (prec->siol.type == CONSTANT)
recGblInitConstantLink(&prec->siol, DBF_USHORT, &prec->sval);
/* Initialize MASK if the user didn't */
if (prec->mask == 0)
prec->mask = (1 << prec->nobt) - 1;
if (pdset->init_record) {
status = pdset->init_record(prec);
if (status == 0) {
epicsUInt16 val = prec->val;
epicsUInt8 *pBn = &prec->b0;
int i;
/* Initialize B0 - BF from VAL */
for (i = 0; i < NUM_BITS; i++, pBn++, val >>= 1)
*pBn = !! (val & 1);
}
}
prec->mlst = prec->val;
prec->oraw = prec->rval;
return(0);
return status;
}
static long process(mbbiDirectRecord *prec)
{
struct mbbidset *pdset = (struct mbbidset *)(prec->dset);
long status;
unsigned char pact=prec->pact;
struct mbbidset *pdset = (struct mbbidset *) prec->dset;
long status;
int pact = prec->pact;
if( (pdset==NULL) || (pdset->read_mbbi==NULL) ) {
prec->pact=TRUE;
recGblRecordError(S_dev_missingSup,(void *)prec,"read_mbbi");
return(S_dev_missingSup);
}
if ((pdset == NULL) || (pdset->read_mbbi == NULL)) {
prec->pact = TRUE;
recGblRecordError(S_dev_missingSup, prec, "read_mbbi");
return S_dev_missingSup;
}
status=readValue(prec); /* read the new value */
/* check if device support set pact */
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
status = readValue(prec);
recGblGetTimeStamp(prec);
/* Done if device support set PACT */
if (!pact && prec->pact)
return 0;
if(status==0) { /* convert the value */
epicsUInt32 rval = prec->rval;
prec->pact = TRUE;
recGblGetTimeStamp(prec);
if(prec->shft>0) rval >>= prec->shft;
prec->val = (unsigned short)rval;
prec->udf=FALSE;
if (status == 0) {
/* Convert RVAL to VAL */
epicsUInt32 rval = prec->rval;
}
else if(status == 2) status = 0;
if (prec->shft > 0)
rval >>= prec->shft;
/* check event list */
monitor(prec);
prec->val = rval;
prec->udf = FALSE;
}
else if (status == 2)
status = 0;
/* process the forward scan link record */
recGblFwdLink(prec);
if (prec->udf)
recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM);
prec->pact=FALSE;
return(status);
monitor(prec);
/* Wrap up */
recGblFwdLink(prec);
prec->pact = FALSE;
return status;
}
static void monitor(mbbiDirectRecord *prec)
{
unsigned short monitor_mask;
epicsUInt16 events = recGblResetAlarms(prec);
epicsUInt16 vl_events = events | DBE_VALUE | DBE_LOG;
epicsUInt16 val = prec->val;
epicsUInt8 *pBn = &prec->b0;
int i;
monitor_mask = recGblResetAlarms(prec);
/* Update B0 - BF from VAL and post monitors */
for (i = 0; i < NUM_BITS; i++, pBn++, val >>= 1) {
epicsUInt8 oBn = *pBn;
/* send out bit field monitors (value change and sevr change) */
refresh_bits(prec, monitor_mask);
*pBn = !! (val & 1);
if (oBn != *pBn)
db_post_events(prec, pBn, vl_events);
else if (events)
db_post_events(prec, pBn, events);
}
/* check for value change */
if (prec->mlst != prec->val) {
/* post events for value change and archive change */
monitor_mask |= (DBE_VALUE | DBE_LOG);
/* update last value monitored */
prec->mlst = prec->val;
}
/* send out monitors connected to the value field */
if (monitor_mask){
db_post_events(prec,&prec->val,monitor_mask);
}
if(prec->oraw!=prec->rval) {
db_post_events(prec,&prec->rval,
monitor_mask|DBE_VALUE|DBE_LOG);
prec->oraw = prec->rval;
}
return;
if (prec->mlst != prec->val) {
events = vl_events;
prec->mlst = prec->val;
}
if (events)
db_post_events(prec, &prec->val, events);
if (prec->oraw != prec->rval) {
db_post_events(prec, &prec->rval, vl_events);
prec->oraw = prec->rval;
}
}
static long readValue(mbbiDirectRecord *prec)
{
long status;
struct mbbidset *pdset = (struct mbbidset *) (prec->dset);
struct mbbidset *pdset = (struct mbbidset *) prec->dset;
long status;
if (prec->pact == TRUE){
status=(*pdset->read_mbbi)(prec);
return(status);
}
if (prec->pact)
return pdset->read_mbbi(prec);
status=dbGetLink(&(prec->siml),DBR_ENUM,
&(prec->simm),0,0);
if (status)
return(status);
status = dbGetLink(&prec->siml, DBR_ENUM, &prec->simm, 0, 0);
if (status)
return status;
if (prec->simm == menuSimmNO){
status=(*pdset->read_mbbi)(prec);
return(status);
}
if (prec->simm == menuSimmYES){
status=dbGetLink(&(prec->siol),
DBR_ULONG,&(prec->sval),0,0);
if (status==0){
prec->val=(unsigned short)prec->sval;
prec->udf=FALSE;
}
status=2; /* don't convert */
}
else if (prec->simm == menuSimmRAW){
status=dbGetLink(&(prec->siol),
DBR_ULONG,&(prec->sval),0,0);
if (status==0){
prec->rval=prec->sval;
prec->udf=FALSE;
}
status=0; /* convert since we've written RVAL */
} else {
status=-1;
recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
return(status);
}
recGblSetSevr(prec,SIMM_ALARM,prec->sims);
switch (prec->simm) {
case menuSimmNO:
return pdset->read_mbbi(prec);
return(status);
case menuSimmYES:
status = dbGetLink(&prec->siol, DBR_ULONG, &prec->sval, 0, 0);
if (status == 0) {
prec->val = prec->sval;
prec->udf = FALSE;
}
status = 2; /* Don't convert */
break;
case menuSimmRAW:
status = dbGetLink(&prec->siol, DBR_ULONG, &prec->sval, 0, 0);
if (status == 0) {
prec->rval = prec->sval;
prec->udf = FALSE;
}
status = 0; /* Convert RVAL */
break;
default:
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
return -1;
}
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
return status;
}

View File

@@ -1,20 +1,20 @@
/*************************************************************************\
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos 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.
\*************************************************************************/
/* $Revision-Id$ */
/* recMbboDirect.c - Record Support for mbboDirect records */
/* mbboDirectRecord.c - Record Support for mbboDirect records */
/*
* Original Author: Bob Dalesio
* Date: 10-06-93
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -22,7 +22,7 @@
#include <string.h>
#include "dbDefs.h"
#include "epicsPrint.h"
#include "errlog.h"
#include "alarm.h"
#include "dbAccess.h"
#include "dbEvent.h"
@@ -59,35 +59,35 @@ static long special(DBADDR *, int);
#define get_control_double NULL
#define get_alarm_double NULL
rset mbboDirectRSET={
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_control_double,
get_alarm_double
rset mbboDirectRSET = {
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_control_double,
get_alarm_double
};
epicsExportAddress(rset,mbboDirectRSET);
epicsExportAddress(rset, mbboDirectRSET);
struct mbbodset { /* multi bit binary output dset */
long number;
DEVSUPFUN dev_report;
DEVSUPFUN init;
DEVSUPFUN init_record; /*returns: (0,2)=>(success,success no convert)*/
DEVSUPFUN get_ioint_info;
DEVSUPFUN write_mbbo; /*returns: (0,2)=>(success,success no convert)*/
long number;
DEVSUPFUN dev_report;
DEVSUPFUN init;
DEVSUPFUN init_record; /*returns: (0, 2)=>(success, success no convert)*/
DEVSUPFUN get_ioint_info;
DEVSUPFUN write_mbbo; /*returns: (0, 2)=>(success, success no convert)*/
};
@@ -95,264 +95,268 @@ static void convert(mbboDirectRecord *);
static void monitor(mbboDirectRecord *);
static long writeValue(mbboDirectRecord *);
#define NUM_BITS 16
#define NUM_BITS 16
static long init_record(mbboDirectRecord *prec, int pass)
{
struct mbbodset *pdset;
struct mbbodset *pdset = (struct mbbodset *) prec->dset;
long status = 0;
int i;
if (pass==0) return(0);
if (pass == 0)
return 0;
/* mbboDirect.siml must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siml.type == CONSTANT) {
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
if (!pdset) {
recGblRecordError(S_dev_noDSET, prec, "mbboDirect: init_record");
return S_dev_noDSET;
}
if(!(pdset = (struct mbbodset *)(prec->dset))) {
recGblRecordError(S_dev_noDSET,(void *)prec,"mbboDirect: init_record");
return(S_dev_noDSET);
if ((pdset->number < 5) || (pdset->write_mbbo == NULL)) {
recGblRecordError(S_dev_missingSup, prec, "mbboDirect: init_record");
return S_dev_missingSup;
}
/* must have write_mbbo function defined */
if( (pdset->number < 5) || (pdset->write_mbbo == NULL) ) {
recGblRecordError(S_dev_missingSup,(void *)prec,"mbboDirect: init_record");
return(S_dev_missingSup);
}
if (prec->dol.type == CONSTANT){
if(recGblInitConstantLink(&prec->dol,DBF_USHORT,&prec->val))
prec->udf = FALSE;
}
/* initialize mask*/
prec->mask = 0;
for (i=0; i<prec->nobt; i++) {
prec->mask <<= 1; /* shift left 1 bit*/
prec->mask |= 1; /* set low order bit*/
}
if(pdset->init_record) {
epicsUInt32 rval;
status=(*pdset->init_record)(prec);
/* init_record might set status */
if(status==0){
rval = prec->rval;
if(prec->shft>0) rval >>= prec->shft;
prec->val = (unsigned short)rval;
prec->udf = FALSE;
} else if (status == 2) status = 0;
if (prec->siml.type == CONSTANT)
recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
if (prec->dol.type == CONSTANT)
if (recGblInitConstantLink(&prec->dol, DBF_USHORT, &prec->val))
prec->udf = FALSE;
/* Initialize MASK if the user didn't */
if (prec->mask == 0)
prec->mask = (1 << prec->nobt) - 1;
if (pdset->init_record) {
status = pdset->init_record(prec);
if (status == 0) {
/* Convert initial read-back */
epicsUInt32 rval = prec->rval;
if (prec->shft > 0)
rval >>= prec->shft;
prec->val = rval;
prec->udf = FALSE;
}
else if (status == 2)
status = 0;
}
if (!prec->udf &&
prec->omsl == menuOmslsupervisory) {
/* Set initial B0 - BF from VAL */
epicsUInt16 val = prec->val;
epicsUInt8 *pBn = &prec->b0;
int i;
for (i = 0; i < NUM_BITS; i++) {
*pBn++ = !! (val & 1);
val >>= 1;
}
}
prec->mlst = prec->val;
prec->oraw = prec->rval;
prec->orbv = prec->rbv;
return(status);
return status;
}
static long process(mbboDirectRecord *prec)
{
struct mbbodset *pdset = (struct mbbodset *)(prec->dset);
long status=0;
unsigned char pact=prec->pact;
struct mbbodset *pdset = (struct mbbodset *)(prec->dset);
long status = 0;
int pact = prec->pact;
if( (pdset==NULL) || (pdset->write_mbbo==NULL) ) {
prec->pact=TRUE;
recGblRecordError(S_dev_missingSup,(void *)prec,"write_mbbo");
return(S_dev_missingSup);
if ((pdset == NULL) || (pdset->write_mbbo == NULL)) {
prec->pact = TRUE;
recGblRecordError(S_dev_missingSup, prec, "write_mbbo");
return S_dev_missingSup;
}
if (!prec->pact) {
if(prec->dol.type!=CONSTANT && prec->omsl==menuOmslclosed_loop){
long status;
unsigned short val;
if (!pact) {
if (prec->dol.type != CONSTANT &&
prec->omsl == menuOmslclosed_loop) {
epicsUInt16 val;
status = dbGetLink(&prec->dol,DBR_USHORT,&val,0,0);
if(status==0) {
prec->val= val;
prec->udf= FALSE;
}
else {
recGblSetSevr(prec,LINK_ALARM,INVALID_ALARM);
goto CONTINUE;
}
}
if(prec->udf) {
recGblSetSevr(prec,UDF_ALARM,INVALID_ALARM);
goto CONTINUE;
}
if(prec->nsev < INVALID_ALARM
&& prec->sevr == INVALID_ALARM
&& prec->omsl == menuOmslsupervisory) {
/* reload value field with B0 - B15 */
int offset = 1, i;
unsigned char *bit = &(prec->b0);
for (i=0; i<NUM_BITS; i++, offset = offset << 1, bit++) {
if (*bit)
prec->val |= offset;
else
prec->val &= ~offset;
}
}
/* convert val to rval */
convert(prec);
if (dbGetLink(&prec->dol, DBR_USHORT, &val, 0, 0)) {
recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
goto CONTINUE;
}
prec->val = val;
}
else if (prec->omsl == menuOmslsupervisory) {
epicsUInt8 *pBn = &prec->b0;
epicsUInt16 val = 0;
epicsUInt16 bit = 1;
int i;
/* Construct VAL from B0 - BF */
for (i = 0; i < NUM_BITS; i++, bit <<= 1)
if (*pBn++)
val |= bit;
prec->val = val;
}
else if (prec->udf) {
recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM);
goto CONTINUE;
}
prec->udf = FALSE;
/* Convert VAL to RVAL */
convert(prec);
}
CONTINUE:
if (prec->nsev < INVALID_ALARM )
status=writeValue(prec); /* write the new value */
else
switch (prec->ivoa) {
case (menuIvoaContinue_normally) :
status=writeValue(prec); /* write the new value */
break;
case (menuIvoaDon_t_drive_outputs) :
break;
case (menuIvoaSet_output_to_IVOV) :
if (prec->pact == FALSE){
prec->val=prec->ivov;
convert(prec);
}
status=writeValue(prec); /* write the new value */
break;
default :
status=-1;
recGblRecordError(S_db_badField,(void *)prec,
"mbboDirect: process Illegal IVOA field");
}
if (prec->nsev < INVALID_ALARM)
status = writeValue(prec);
else {
switch (prec->ivoa) {
case menuIvoaSet_output_to_IVOV:
if (!prec->pact) {
prec->val = prec->ivov;
convert(prec);
}
/* No break, fall through... */
case menuIvoaContinue_normally:
status = writeValue(prec);
break;
case menuIvoaDon_t_drive_outputs:
break;
default:
status = -1;
recGblRecordError(S_db_badField, prec,
"mbboDirect: process Illegal IVOA field");
}
}
/* Done if device support set PACT */
if (!pact && prec->pact)
return 0;
/* check if device support set pact */
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
recGblGetTimeStamp(prec);
/* check event list */
monitor(prec);
/* process the forward scan link record */
/* Wrap up */
recGblFwdLink(prec);
prec->pact=FALSE;
return(status);
prec->pact = FALSE;
return status;
}
static long special(DBADDR *paddr, int after)
{
mbboDirectRecord *prec = (mbboDirectRecord *)(paddr->precord);
int special_type = paddr->special, offset = 1, i;
unsigned char *bit;
mbboDirectRecord *prec = (mbboDirectRecord *) paddr->precord;
if(!after) return(0);
switch(special_type) {
case(SPC_MOD):
/*
* Set a bit in VAL corresponding to the bit changed
* offset equals the offset in bit array. Only do
* this if in supervisory mode.
*/
if (prec->omsl == menuOmslclosed_loop)
return(0);
if (!after)
return 0;
offset = 1 << (((unsigned char *)paddr->pfield) - &(prec->b0));
if (*((char *)paddr->pfield)) {
/* set field */
prec->val |= offset;
}
else {
/* zero field */
prec->val &= ~offset;
}
prec->udf = FALSE;
convert(prec);
return(0);
case(SPC_RESET):
/*
* If OMSL changes from closed_loop to supervisory,
* reload value field with B0 - B15
*/
bit = &(prec->b0);
switch (paddr->special) {
case SPC_MOD: /* Bn field modified */
if (prec->omsl == menuOmslsupervisory) {
for (i=0; i<NUM_BITS; i++, offset = offset << 1, bit++) {
if (*bit)
prec->val |= offset;
else
prec->val &= ~offset;
/* Adjust VAL corresponding to the bit changed */
epicsUInt8 *pBn = (epicsUInt8 *) paddr->pfield;
int bit = 1 << (pBn - &prec->b0);
if (*pBn)
prec->val |= bit;
else
prec->val &= ~bit;
prec->udf = FALSE;
convert(prec);
}
break;
case SPC_RESET: /* OMSL field modified */
if (prec->omsl == menuOmslclosed_loop) {
/* Construct VAL from B0 - BF */
epicsUInt8 *pBn = &prec->b0;
epicsUInt16 val = 0, bit = 1;
int i;
for (i = 0; i < NUM_BITS; i++, bit <<= 1)
if (*pBn++)
val |= bit;
prec->val = val;
}
else if (prec->omsl == menuOmslsupervisory) {
/* Set B0 - BF from VAL and post monitors */
epicsUInt16 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);
}
}
prec->udf = FALSE;
break;
return(0);
default:
recGblDbaddrError(S_db_badChoice,paddr,"mbboDirect: special");
return(S_db_badChoice);
default:
recGblDbaddrError(S_db_badChoice, paddr, "mbboDirect: special");
return S_db_badChoice;
}
prec->udf = FALSE;
return 0;
}
static void monitor(mbboDirectRecord *prec)
{
unsigned short monitor_mask;
epicsUInt16 events = recGblResetAlarms(prec);
monitor_mask = 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);
/* check for value change */
if (prec->mlst != prec->val){
/* post events for value change and archive change */
monitor_mask |= (DBE_VALUE | DBE_LOG);
/* update last value monitored */
prec->mlst = prec->val;
}
/* send out monitors connected to the value field */
if (monitor_mask){
db_post_events(prec,&prec->val,monitor_mask);
}
if(prec->oraw!=prec->rval) {
db_post_events(prec,&prec->rval,
monitor_mask|DBE_VALUE|DBE_LOG);
prec->oraw = prec->rval;
}
if(prec->orbv!=prec->rbv) {
db_post_events(prec,&prec->rbv,
monitor_mask|DBE_VALUE|DBE_LOG);
prec->orbv = prec->rbv;
}
return;
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;
}
}
static void convert(mbboDirectRecord *prec)
{
/* convert val to rval */
prec->rval = (epicsUInt32)(prec->val);
if(prec->shft>0)
prec->rval <<= prec->shft;
/* Convert VAL to RVAL */
prec->rval = prec->val;
return;
if (prec->shft > 0)
prec->rval <<= prec->shft;
}
static long writeValue(mbboDirectRecord *prec)
{
long status;
struct mbbodset *pdset = (struct mbbodset *) (prec->dset);
long status;
struct mbbodset *pdset = (struct mbbodset *) prec->dset;
if (prec->pact == TRUE){
status=(*pdset->write_mbbo)(prec);
return(status);
}
if (prec->pact)
return pdset->write_mbbo(prec);
status=dbGetLink(&(prec->siml),
DBR_ENUM,&(prec->simm),0,0);
if (status)
return(status);
status = dbGetLink(&prec->siml, DBR_ENUM, &prec->simm, 0, 0);
if (status)
return status;
if (prec->simm == menuYesNoNO){
status=(*pdset->write_mbbo)(prec);
return(status);
}
if (prec->simm == menuYesNoYES){
status=dbPutLink(&prec->siol,DBR_USHORT,
&prec->val,1);
} else {
status=-1;
recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
return(status);
}
recGblSetSevr(prec,SIMM_ALARM,prec->sims);
switch (prec->simm) {
case menuYesNoNO:
return pdset->write_mbbo(prec);
return(status);
case menuYesNoYES:
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
return dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
default:
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
return -1;
}
}