diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index c8f2bc658..1f8c12234 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -17,6 +17,18 @@ --> +
Records that support simulation mode have two new fields, SSCN +(Simulation Scan Mode) and SDLY (Simulation Delay). SSCN is a +menu field that provides an alternate value for the SCAN field to be +used while the record is in simulation mode. This is especially useful for I/O +scanned records, for which simulation mode was not working at all. Setting +SDLY to a positive value makes the record process asynchronously in +simulation mode, with the second stage processing happening after the specified +time (in seconds).
+ +This change permits IOCs to be built that omit the CA server (RSRV) by
diff --git a/src/ioc/db/recGbl.c b/src/ioc/db/recGbl.c
index 337ed7875..29d7a2d46 100644
--- a/src/ioc/db/recGbl.c
+++ b/src/ioc/db/recGbl.c
@@ -29,9 +29,11 @@
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
+#include "dbStaticLib.h"
#include "dbAddr.h"
#include "dbBase.h"
#include "dbCommon.h"
+#include "menuSimm.h"
#include "dbEvent.h"
#include "db_field_log.h"
#include "dbFldTypes.h"
@@ -255,7 +257,12 @@ void recGblFwdLink(void *precord)
void recGblGetTimeStamp(void *pvoid)
{
- dbCommon* prec = (dbCommon*)pvoid;
+ recGblGetTimeStampSimm(pvoid, menuSimmNO, 0);
+}
+
+void recGblGetTimeStampSimm(void *pvoid, const epicsEnum16 simm, struct link *siol)
+{
+ dbCommon *prec = (dbCommon *)pvoid;
struct link *plink = &prec->tsel;
if (!dbLinkIsConstant(plink)) {
@@ -269,8 +276,22 @@ void recGblGetTimeStamp(void *pvoid)
}
if (prec->tse != epicsTimeEventDeviceTime) {
if (epicsTimeGetEvent(&prec->time, prec->tse))
- errlogPrintf("recGblGetTimeStamp: epicsTimeGetEvent failed, %s.TSE = %d\n",
- prec->name, prec->tse);
+ errlogPrintf("recGblGetTimeStampSimm: epicsTimeGetEvent failed, %s.TSE = %d\n",
+ prec->name, prec->tse);
+ } else {
+ if (simm != menuSimmNO) {
+ if (siol && !dbLinkIsConstant(siol)) {
+ if (dbGetTimeStamp(siol, &prec->time))
+ errlogPrintf("recGblGetTimeStampSimm: dbGetTimeStamp (sim mode) failed, %s.SIOL = %s\n",
+ prec->name, siol->value.pv_link.pvname);
+ return;
+ } else {
+ if (epicsTimeGetCurrent(&prec->time))
+ errlogPrintf("recGblGetTimeStampSimm: epicsTimeGetCurrent (sim mode) failed for %s.\n",
+ prec->name);
+ return;
+ }
+ }
}
}
@@ -349,3 +370,41 @@ static void getMaxRangeValues(short field_type, double *pupper_limit,
}
return;
}
+
+void recGblSaveSimm(const epicsEnum16 sscn,
+ epicsEnum16 *poldsimm, const epicsEnum16 simm) {
+ if (sscn == USHRT_MAX) return;
+ *poldsimm = simm;
+}
+
+void recGblCheckSimm(struct dbCommon *pcommon, epicsEnum16 *psscn,
+ const epicsEnum16 oldsimm, const epicsEnum16 simm) {
+ if (*psscn == USHRT_MAX) return;
+ if (simm != oldsimm) {
+ epicsUInt16 scan = pcommon->scan;
+ scanDelete(pcommon);
+ pcommon->scan = *psscn;
+ scanAdd(pcommon);
+ *psscn = scan;
+ }
+}
+
+void recGblInitSimm(struct dbCommon *pcommon, epicsEnum16 *psscn,
+ epicsEnum16 *poldsimm, epicsEnum16 *psimm, struct link *psiml) {
+ if (dbLinkIsConstant(psiml)) {
+ recGblSaveSimm(*psscn, poldsimm, *psimm);
+ dbLoadLink(psiml, DBF_USHORT, psimm);
+ recGblCheckSimm(pcommon, psscn, *poldsimm, *psimm);
+ }
+}
+
+long recGblGetSimm(struct dbCommon *pcommon, epicsEnum16 *psscn,
+ epicsEnum16 *poldsimm, epicsEnum16 *psimm, struct link *psiml) {
+ long status;
+
+ recGblSaveSimm(*psscn, poldsimm, *psimm);
+ status = dbGetLink(psiml, DBR_USHORT, psimm, 0, 0);
+ if (status) return status;
+ recGblCheckSimm(pcommon, psscn, *poldsimm, *psimm);
+ return 0;
+}
diff --git a/src/ioc/db/recGbl.h b/src/ioc/db/recGbl.h
index 171c00964..20de9568a 100644
--- a/src/ioc/db/recGbl.h
+++ b/src/ioc/db/recGbl.h
@@ -63,8 +63,17 @@ epicsShareFunc void recGblInheritSevr(int msMode, void *precord, epicsEnum16 sta
epicsEnum16 sevr);
epicsShareFunc void recGblFwdLink(void *precord);
epicsShareFunc void recGblGetTimeStamp(void *precord);
+epicsShareFunc void recGblGetTimeStampSimm(void *prec, const epicsEnum16 simm, struct link *siol);
epicsShareFunc void recGblCheckDeadband(epicsFloat64 *poldval, const epicsFloat64 newval,
const epicsFloat64 deadband, unsigned *monitor_mask, const unsigned add_mask);
+epicsShareFunc void recGblSaveSimm(const epicsEnum16 sscn,
+ epicsEnum16 *poldsimm, const epicsEnum16 simm);
+epicsShareFunc void recGblCheckSimm(struct dbCommon *prec, epicsEnum16 *psscn,
+ const epicsEnum16 oldsimm, const epicsEnum16 simm);
+epicsShareFunc void recGblInitSimm(struct dbCommon *prec, epicsEnum16 *psscn,
+ epicsEnum16 *poldsimm, epicsEnum16 *psimm, struct link *psiml);
+epicsShareFunc long recGblGetSimm(struct dbCommon *prec, epicsEnum16 *psscn,
+ epicsEnum16 *poldsimm, epicsEnum16 *psimm, struct link *psiml);
#ifdef __cplusplus
}
diff --git a/src/ioc/dbStatic/dbStaticRun.c b/src/ioc/dbStatic/dbStaticRun.c
index efc672270..d3817ffc5 100644
--- a/src/ioc/dbStatic/dbStaticRun.c
+++ b/src/ioc/dbStatic/dbStaticRun.c
@@ -483,7 +483,7 @@ long dbPutStringNum(DBENTRY *pdbentry, const char *pstring)
return status;
index = dbGetNMenuChoices(pdbentry);
- if (value > index && index > 0)
+ if (value > index && index > 0 && value < USHRT_MAX)
return S_dbLib_badField;
*field = value;
diff --git a/src/std/rec/aaiRecord.c b/src/std/rec/aaiRecord.c
index 0dfed346c..230c060c4 100644
--- a/src/std/rec/aaiRecord.c
+++ b/src/std/rec/aaiRecord.c
@@ -31,6 +31,7 @@
#include "epicsPrint.h"
#include "epicsString.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
@@ -40,6 +41,7 @@
#include "recSup.h"
#include "recGbl.h"
#include "cantProceed.h"
+#include "special.h"
#include "menuYesNo.h"
#define GEN_SIZE_OFFSET
@@ -52,7 +54,7 @@
#define initialize NULL
static long init_record(struct dbCommon *, int);
static long process(struct dbCommon *);
-#define special NULL
+static long special(DBADDR *, int);
#define get_value NULL
static long cvt_dbaddr(DBADDR *);
static long get_array_info(DBADDR *, long *, long *);
@@ -141,8 +143,8 @@ static long init_record(struct dbCommon *pcommon, int pass)
return 0;
}
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
-
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+
/* must have read_aai function defined */
if (pdset->number < 5 || pdset->read_aai == NULL) {
recGblRecordError(S_dev_missingSup, prec, "aai: init_record");
@@ -169,7 +171,7 @@ static long process(struct dbCommon *pcommon)
prec->pact = TRUE;
prec->udf = FALSE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
monitor(prec);
/* process the forward scan link record */
@@ -179,6 +181,26 @@ static long process(struct dbCommon *pcommon)
return status;
}
+static long special(DBADDR *paddr, int after)
+{
+ aaiRecord *prec = (aaiRecord *)(paddr->precord);
+ int special_type = paddr->special;
+
+ switch(special_type) {
+ case(SPC_MOD):
+ if (dbGetFieldIndex(paddr) == aaiRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return(0);
+ }
+ default:
+ recGblDbaddrError(S_db_badChoice, paddr, "aai: special");
+ return(S_db_badChoice);
+ }
+}
+
static long cvt_dbaddr(DBADDR *paddr)
{
aaiRecord *prec = (aaiRecord *)paddr->precord;
@@ -313,35 +335,49 @@ static void monitor(aaiRecord *prec)
static long readValue(aaiRecord *prec)
{
- long status;
- struct aaidset *pdset = (struct aaidset *)prec->dset;
+ struct aaidset *pdset = (struct aaidset *) prec->dset;
+ long status = 0;
- if (prec->pact == TRUE){
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
+
+ switch (prec->simm) {
+ case menuYesNoNO:
status = pdset->read_aai(prec);
- return status;
- }
+ break;
- status = dbGetLink(&prec->siml, DBR_ENUM, &prec->simm, 0, 0);
- if (status)
- return status;
-
- if (prec->simm == menuYesNoNO){
- return pdset->read_aai(prec);
- }
-
- if (prec->simm == menuYesNoYES){
- /* Device suport is responsible for buffer
- which might be read-only so we may not be
- allowed to call dbGetLink on it.
- Maybe also device support has an advanced
- simulation mode.
- Thus call device now.
- */
+ case menuYesNoYES: {
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
- return pdset->read_aai(prec);
+ if (prec->pact || (prec->sdly < 0.)) {
+ /* Device suport is responsible for buffer
+ which might be read-only so we may not be
+ allowed to call dbGetLink on it.
+ Maybe also device support has an advanced
+ simulation mode.
+ Thus call device now.
+
+ Reading through SIOL is handled in Soft Channel Device Support
+ */
+ status = pdset->read_aai(prec);
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
}
- recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
- return -1;
-}
+ default:
+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
+ status = -1;
+ }
+ return status;
+}
diff --git a/src/std/rec/aaiRecord.dbd b/src/std/rec/aaiRecord.dbd
index 06ab7f7b8..15db6d360 100644
--- a/src/std/rec/aaiRecord.dbd
+++ b/src/std/rec/aaiRecord.dbd
@@ -76,28 +76,55 @@ recordtype(aai) {
interest(4)
extra("void * bptr")
}
- field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
- promptgroup("90 - Simulate")
- interest(1)
- }
- field(SIMM,DBF_MENU) {
- prompt("Simulation Mode")
- interest(1)
- menu(menuYesNo)
- }
- field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
- promptgroup("90 - Simulate")
- interest(2)
- menu(menuAlarmSevr)
- }
- field(SIOL,DBF_INLINK) {
- prompt("Sim Input Specifctn")
- promptgroup("90 - Simulate")
- interest(1)
- }
- field(MPST,DBF_MENU) {
+ field(SIML,DBF_INLINK) {
+ prompt("Simulation Mode Link")
+ promptgroup("90 - Simulate")
+ interest(1)
+ }
+ field(SIMM,DBF_MENU) {
+ prompt("Simulation Mode")
+ special(SPC_MOD)
+ interest(1)
+ menu(menuYesNo)
+ }
+ field(SIMS,DBF_MENU) {
+ prompt("Simulation Mode Severity")
+ promptgroup("90 - Simulate")
+ interest(2)
+ menu(menuAlarmSevr)
+ }
+ field(SIOL,DBF_INLINK) {
+ prompt("Simulation Input Link")
+ promptgroup("90 - Simulate")
+ interest(1)
+ }
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
+ field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
diff --git a/src/std/rec/aaoRecord.c b/src/std/rec/aaoRecord.c
index 1cc2541eb..68a76a66a 100644
--- a/src/std/rec/aaoRecord.c
+++ b/src/std/rec/aaoRecord.c
@@ -31,6 +31,7 @@
#include "epicsPrint.h"
#include "epicsString.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
@@ -39,6 +40,7 @@
#include "errMdef.h"
#include "recSup.h"
#include "recGbl.h"
+#include "special.h"
#include "cantProceed.h"
#include "menuYesNo.h"
@@ -52,7 +54,7 @@
#define initialize NULL
static long init_record(struct dbCommon *, int);
static long process(struct dbCommon *);
-#define special NULL
+static long special(DBADDR *, int);
#define get_value NULL
static long cvt_dbaddr(DBADDR *);
static long get_array_info(DBADDR *, long *, long *);
@@ -141,7 +143,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
return 0;
}
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
/* must have write_aao function defined */
if (pdset->number < 5 || pdset->write_aao == NULL) {
@@ -169,7 +171,7 @@ static long process(struct dbCommon *pcommon)
prec->pact = TRUE;
prec->udf = FALSE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, NULL);
monitor(prec);
/* process the forward scan link record */
@@ -179,6 +181,26 @@ static long process(struct dbCommon *pcommon)
return status;
}
+static long special(DBADDR *paddr, int after)
+{
+ aaoRecord *prec = (aaoRecord *)(paddr->precord);
+ int special_type = paddr->special;
+
+ switch(special_type) {
+ case(SPC_MOD):
+ if (dbGetFieldIndex(paddr) == aaoRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return(0);
+ }
+ default:
+ recGblDbaddrError(S_db_badChoice, paddr, "aao: special");
+ return(S_db_badChoice);
+ }
+}
+
static long cvt_dbaddr(DBADDR *paddr)
{
aaoRecord *prec = (aaoRecord *)paddr->precord;
@@ -313,33 +335,49 @@ static void monitor(aaoRecord *prec)
static long writeValue(aaoRecord *prec)
{
- long status;
- struct aaodset *pdset = (struct aaodset *)prec->dset;
+ struct aaodset *pdset = (struct aaodset *) prec->dset;
+ long status = 0;
- if (prec->pact == TRUE) {
- /* no asyn allowed, pact true means do not process */
- return 0;
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
}
- status = dbGetLink(&prec->siml, DBR_ENUM, &prec->simm, 0, 0);
- if (status)
- return status;
+ switch (prec->simm) {
+ case menuYesNoNO:
+ status = pdset->write_aao(prec);
+ break;
- if (prec->simm == menuYesNoNO) {
- return pdset->write_aao(prec);
- }
- if (prec->simm == menuYesNoYES) {
- /* Device suport is responsible for buffer
- which might be write-only so we may not be
- allowed to call dbPutLink on it.
- Maybe also device support has an advanced
- simulation mode.
- Thus call device now.
- */
+ case menuYesNoYES: {
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
- return pdset->write_aao(prec);
- }
- recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
- return -1;
-}
+ if (prec->pact || (prec->sdly < 0.)) {
+ /* Device suport is responsible for buffer
+ which might be write-only so we may not be
+ allowed to call dbPutLink on it.
+ Maybe also device support has an advanced
+ simulation mode.
+ Thus call device now.
+ Writing through SIOL is handled in Soft Channel Device Support
+ */
+ status = pdset->write_aao(prec);
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
+ }
+
+ default:
+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
+ status = -1;
+ }
+
+ return status;
+}
diff --git a/src/std/rec/aaoRecord.dbd b/src/std/rec/aaoRecord.dbd
index 57d842f4f..a1731a3cb 100644
--- a/src/std/rec/aaoRecord.dbd
+++ b/src/std/rec/aaoRecord.dbd
@@ -76,28 +76,55 @@ recordtype(aao) {
interest(4)
extra("void * bptr")
}
- field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
- promptgroup("90 - Simulate")
- interest(1)
- }
- field(SIMM,DBF_MENU) {
- prompt("Simulation Mode")
- interest(1)
- menu(menuYesNo)
- }
- field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
- promptgroup("90 - Simulate")
- interest(2)
- menu(menuAlarmSevr)
- }
- field(SIOL,DBF_OUTLINK) {
- prompt("Sim Output Specifctn")
- promptgroup("90 - Simulate")
- interest(1)
- }
- field(MPST,DBF_MENU) {
+ field(SIML,DBF_INLINK) {
+ prompt("Simulation Mode Link")
+ promptgroup("90 - Simulate")
+ interest(1)
+ }
+ field(SIMM,DBF_MENU) {
+ prompt("Simulation Mode")
+ special(SPC_MOD)
+ interest(1)
+ menu(menuYesNo)
+ }
+ field(SIMS,DBF_MENU) {
+ prompt("Simulation Mode Severity")
+ promptgroup("90 - Simulate")
+ interest(2)
+ menu(menuAlarmSevr)
+ }
+ field(SIOL,DBF_OUTLINK) {
+ prompt("Simulation Output Link")
+ promptgroup("90 - Simulate")
+ interest(1)
+ }
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
+ field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
diff --git a/src/std/rec/aiRecord.c b/src/std/rec/aiRecord.c
index 81f730f6d..500193360 100644
--- a/src/std/rec/aiRecord.c
+++ b/src/std/rec/aiRecord.c
@@ -24,6 +24,7 @@
#include "errlog.h"
#include "epicsMath.h"
#include "alarm.h"
+#include "callback.h"
#include "cvtTable.h"
#include "dbAccess.h"
#include "dbScan.h"
@@ -96,22 +97,21 @@ typedef struct aidset { /* analog input dset */
DEVSUPFUN special_linconv;
}aidset;
-
static void checkAlarms(aiRecord *prec, epicsTimeStamp *lastTime);
static void convert(aiRecord *prec);
static void monitor(aiRecord *prec);
static long readValue(aiRecord *prec);
-
+
static long init_record(struct dbCommon *pcommon, int pass)
{
struct aiRecord *prec = (struct aiRecord *)pcommon;
aidset *pdset;
double eoff = prec->eoff, eslo = prec->eslo;
- if (pass==0) return(0);
+ if (pass == 0) return 0;
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
- recGblInitConstantLink(&prec->siol,DBF_DOUBLE,&prec->sval);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ recGblInitConstantLink(&prec->siol, DBF_DOUBLE, &prec->sval);
if(!(pdset = (aidset *)(prec->dset))) {
recGblRecordError(S_dev_noDSET,(void *)prec,"ai: init_record");
@@ -147,8 +147,8 @@ static long process(struct dbCommon *pcommon)
{
struct aiRecord *prec = (struct aiRecord *)pcommon;
aidset *pdset = (aidset *)(prec->dset);
- long status;
- unsigned char pact=prec->pact;
+ long status;
+ unsigned char pact=prec->pact;
epicsTimeStamp timeLast;
if( (pdset==NULL) || (pdset->read_ai==NULL) ) {
@@ -163,10 +163,13 @@ static long process(struct dbCommon *pcommon)
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
+
if (status==0) convert(prec);
else if (status==2) status=0;
+ if (status == 0) prec->udf = isnan(prec->val);
+
/* check for alarms */
checkAlarms(prec,&timeLast);
/* check event list */
@@ -187,27 +190,35 @@ static long special(DBADDR *paddr,int after)
switch(special_type) {
case(SPC_LINCONV):
- if(pdset->number<6) {
- recGblDbaddrError(S_db_noMod,paddr,"ai: special");
- return(S_db_noMod);
- }
- prec->init=TRUE;
- if ((prec->linr == menuConvertLINEAR) && pdset->special_linconv) {
- double eoff = prec->eoff;
- double eslo = prec->eslo;
- long status;
- prec->eoff = prec->egul;
- status = (*pdset->special_linconv)(prec,after);
- if (eoff != prec->eoff)
- db_post_events(prec, &prec->eoff, DBE_VALUE|DBE_LOG);
- if (eslo != prec->eslo)
- db_post_events(prec, &prec->eslo, DBE_VALUE|DBE_LOG);
- return(status);
- }
- return(0);
+ if(pdset->number<6) {
+ recGblDbaddrError(S_db_noMod,paddr,"ai: special");
+ return(S_db_noMod);
+ }
+ prec->init=TRUE;
+ if ((prec->linr == menuConvertLINEAR) && pdset->special_linconv) {
+ double eoff = prec->eoff;
+ double eslo = prec->eslo;
+ long status;
+ prec->eoff = prec->egul;
+ status = (*pdset->special_linconv)(prec,after);
+ if (eoff != prec->eoff)
+ db_post_events(prec, &prec->eoff, DBE_VALUE|DBE_LOG);
+ if (eslo != prec->eslo)
+ db_post_events(prec, &prec->eslo, DBE_VALUE|DBE_LOG);
+ return(status);
+ }
+ return(0);
+ case(SPC_MOD):
+ if (dbGetFieldIndex(paddr) == aiRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return(0);
+ }
default:
- recGblDbaddrError(S_db_badChoice,paddr,"ai: special");
- return(S_db_badChoice);
+ recGblDbaddrError(S_db_badChoice,paddr,"ai: special");
+ return(S_db_badChoice);
}
}
@@ -442,7 +453,6 @@ static void convert(aiRecord *prec)
}else{
prec->val = val;
}
- prec->udf = isnan(prec->val);
return;
}
@@ -469,46 +479,50 @@ static void monitor(aiRecord *prec)
static long readValue(aiRecord *prec)
{
- long status;
- aidset *pdset = (aidset *) (prec->dset);
+ aidset *pdset = (aidset *)prec->dset;
+ long status = 0;
- if (prec->pact == TRUE){
- status=(*pdset->read_ai)(prec);
- return(status);
- }
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
- status = dbGetLink(&(prec->siml),DBR_USHORT,&(prec->simm),0,0);
+ switch (prec->simm) {
+ case menuSimmNO:
+ status = pdset->read_ai(prec);
+ break;
- if (status)
- return(status);
+ case menuSimmYES:
+ case menuSimmRAW: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbGetLink(&prec->siol, DBR_DOUBLE, &prec->sval, 0, 0);
+ if (status == 0) {
+ if (prec->simm == menuSimmYES) {
+ prec->val = prec->sval;
+ status = 2; /* don't convert */
+ } else {
+ prec->rval = (long)floor(prec->sval);
+ status = 0; /* convert RVAL */
+ }
+ }
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
+ }
- if (prec->simm == menuSimmNO){
- status=(*pdset->read_ai)(prec);
- return(status);
- }
- if (prec->simm == menuSimmYES){
- status = dbGetLink(&(prec->siol),DBR_DOUBLE,&(prec->sval),0,0);
- if (status==0){
- prec->val=prec->sval;
- prec->udf=isnan(prec->val);
- }
- status=2; /* dont convert */
- }
- else if (prec->simm == menuSimmRAW){
- status = dbGetLink(&(prec->siol),DBR_DOUBLE,&(prec->sval),0,0);
- if (status==0) {
- prec->udf=isnan(prec->sval);
- if (!prec->udf) {
- prec->rval=(long)floor(prec->sval);
- }
- }
- 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);
+ default:
+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
+ status = -1;
+ }
- return(status);
+ return status;
}
diff --git a/src/std/rec/aiRecord.dbd.pod b/src/std/rec/aiRecord.dbd.pod
index 2973ec831..69ca65f3f 100644
--- a/src/std/rec/aiRecord.dbd.pod
+++ b/src/std/rec/aiRecord.dbd.pod
@@ -468,7 +468,7 @@ simulation mode.
=cut
field(SIOL,DBF_INLINK) {
- prompt("Sim. Input Specification")
+ prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
@@ -476,12 +476,13 @@ simulation mode.
prompt("Simulation Value")
}
field(SIML,DBF_INLINK) {
- prompt("Sim. Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
+ special(SPC_MOD)
interest(1)
menu(menuSimm)
}
@@ -491,6 +492,32 @@ simulation mode.
interest(2)
menu(menuAlarmSevr)
}
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
}
=head2 Device Support Interface
diff --git a/src/std/rec/aoRecord.c b/src/std/rec/aoRecord.c
index 0d923af5c..c5a84f615 100644
--- a/src/std/rec/aoRecord.c
+++ b/src/std/rec/aoRecord.c
@@ -24,6 +24,7 @@
#include "epicsPrint.h"
#include "epicsMath.h"
#include "alarm.h"
+#include "callback.h"
#include "cvtTable.h"
#include "dbAccess.h"
#include "dbEvent.h"
@@ -94,7 +95,6 @@ struct aodset { /* analog input dset */
epicsExportAddress(rset,aoRSET);
-
static void checkAlarms(aoRecord *);
static long fetch_value(aoRecord *, double *);
static void convert(aoRecord *, double);
@@ -107,10 +107,11 @@ static long init_record(struct dbCommon *pcommon, int pass)
struct aodset *pdset;
double eoff = prec->eoff, eslo = prec->eslo;
double value;
+ long status = 0;
- if (pass==0) return(0);
+ if (pass == 0) return 0;
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
if(!(pdset = (struct aodset *)(prec->dset))) {
recGblRecordError(S_dev_noDSET,(void *)prec,"ao: init_record");
@@ -132,7 +133,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
}
if (pdset->init_record) {
- long status=(*pdset->init_record)(prec);
+ status = (*pdset->init_record)(prec);
if (prec->linr == menuConvertSLOPE) {
prec->eoff = eoff;
prec->eslo = eslo;
@@ -228,7 +229,7 @@ static long process(struct dbCommon *pcommon)
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, NULL);
/* check event list */
monitor(prec);
@@ -267,6 +268,14 @@ static long special(DBADDR *paddr, int after)
return (status);
}
return (0);
+ case(SPC_MOD):
+ if (dbGetFieldIndex(paddr) == aoRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return(0);
+ }
default:
recGblDbaddrError(S_db_badChoice,paddr,"ao: special");
return(S_db_badChoice);
@@ -546,30 +555,40 @@ static void monitor(aoRecord *prec)
static long writeValue(aoRecord *prec)
{
- long status;
- struct aodset *pdset = (struct aodset *) (prec->dset);
+ struct aodset *pdset = (struct aodset *) prec->dset;
+ long status = 0;
- if (prec->pact == TRUE){
- status=(*pdset->write_ao)(prec);
- return(status);
- }
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
- status = dbGetLink(&prec->siml,DBR_USHORT,&(prec->simm),0,0);
- if (status)
- return(status);
+ switch (prec->simm) {
+ case menuYesNoNO:
+ status = pdset->write_ao(prec);
+ break;
- if (prec->simm == menuYesNoNO){
- status=(*pdset->write_ao)(prec);
- return(status);
- }
- if (prec->simm == menuYesNoYES){
- status = dbPutLink(&(prec->siol),DBR_DOUBLE,&(prec->oval),1);
- } else {
- status=-1;
- recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
- return(status);
- }
- recGblSetSevr(prec,SIMM_ALARM,prec->sims);
+ case menuYesNoYES: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbPutLink(&prec->siol, DBR_DOUBLE, &prec->oval, 1);
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
+ }
- return(status);
+ default:
+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
+ status = -1;
+ }
+
+ return status;
}
diff --git a/src/std/rec/aoRecord.dbd.pod b/src/std/rec/aoRecord.dbd.pod
index 41467dcd3..f2361df7e 100644
--- a/src/std/rec/aoRecord.dbd.pod
+++ b/src/std/rec/aoRecord.dbd.pod
@@ -528,26 +528,53 @@ information on these fields.
interest(3)
}
field(SIOL,DBF_OUTLINK) {
- prompt("Sim Output Specifctn")
+ prompt("Simulation Output Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
+ special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
field(IVOA,DBF_MENU) {
prompt("INVALID output action")
promptgroup("50 - Output")
diff --git a/src/std/rec/biRecord.c b/src/std/rec/biRecord.c
index 7afea3d9d..be700a56a 100644
--- a/src/std/rec/biRecord.c
+++ b/src/std/rec/biRecord.c
@@ -23,6 +23,7 @@
#include "dbDefs.h"
#include "epicsPrint.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbFldTypes.h"
#include "dbEvent.h"
@@ -43,7 +44,7 @@
#define initialize NULL
static long init_record(struct dbCommon *, int);
static long process(struct dbCommon *);
-#define special NULL
+static long special(DBADDR *, int);
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
@@ -95,10 +96,11 @@ static long init_record(struct dbCommon *pcommon, int pass)
struct bidset *pdset;
long status;
- if (pass==0) return(0);
+ if (pass == 0) return 0;
+
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ recGblInitConstantLink(&prec->siol, DBF_USHORT, &prec->sval);
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
- recGblInitConstantLink(&prec->siol,DBF_USHORT,&prec->sval);
if(!(pdset = (struct bidset *)(prec->dset))) {
recGblRecordError(S_dev_noDSET,(void *)prec,"bi: init_record");
return(S_dev_noDSET);
@@ -135,8 +137,9 @@ static long process(struct dbCommon *pcommon)
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
- if(status==0) { /* convert rval to val */
+ recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
+
+ if(status==0) { /* convert rval to val */
if(prec->rval==0) prec->val =0;
else prec->val = 1;
prec->udf = FALSE;
@@ -153,6 +156,26 @@ static long process(struct dbCommon *pcommon)
return(status);
}
+static long special(DBADDR *paddr, int after)
+{
+ biRecord *prec = (biRecord *)(paddr->precord);
+ int special_type = paddr->special;
+
+ switch(special_type) {
+ case(SPC_MOD):
+ if (dbGetFieldIndex(paddr) == biRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return(0);
+ }
+ default:
+ recGblDbaddrError(S_db_badChoice, paddr, "bi: special");
+ return(S_db_badChoice);
+ }
+}
+
static long get_enum_str(const DBADDR *paddr, char *pstring)
{
biRecord *prec=(biRecord *)paddr->precord;
@@ -252,43 +275,50 @@ static void monitor(biRecord *prec)
static long readValue(biRecord *prec)
{
- long status;
- struct bidset *pdset = (struct bidset *) (prec->dset);
+ struct bidset *pdset = (struct bidset *)prec->dset;
+ long status = 0;
- if (prec->pact == TRUE){
- status=(*pdset->read_bi)(prec);
- return(status);
- }
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
- status = dbGetLink(&(prec->siml),DBR_USHORT, &(prec->simm),0,0);
- if (status)
- return(status);
+ switch (prec->simm) {
+ case menuSimmNO:
+ status = pdset->read_bi(prec);
+ break;
- if (prec->simm == menuSimmNO){
- status=(*pdset->read_bi)(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; /* dont 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);
+ case menuSimmYES:
+ case menuSimmRAW: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbGetLink(&prec->siol, DBR_ULONG, &prec->sval, 0, 0);
+ if (status == 0) {
+ if (prec->simm == menuSimmYES) {
+ prec->val = prec->sval;
+ status = 2; /* Don't convert */
+ } else {
+ prec->rval = (unsigned short) prec->sval;
+ }
+ prec->udf = FALSE;
+ }
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
+ }
- return(status);
+ default:
+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
+ status = -1;
+ }
+
+ return status;
}
diff --git a/src/std/rec/biRecord.dbd b/src/std/rec/biRecord.dbd
index fb3588fb1..1646d5df1 100644
--- a/src/std/rec/biRecord.dbd
+++ b/src/std/rec/biRecord.dbd
@@ -81,7 +81,7 @@ recordtype(bi) {
interest(3)
}
field(SIOL,DBF_INLINK) {
- prompt("Sim Input Specifctn")
+ prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
@@ -89,19 +89,46 @@ recordtype(bi) {
prompt("Simulation Value")
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
- interest(1)
+ special(SPC_MOD)
+ interest(1)
menu(menuSimm)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
}
diff --git a/src/std/rec/boRecord.c b/src/std/rec/boRecord.c
index 8f60a0be5..5fb881f55 100644
--- a/src/std/rec/boRecord.c
+++ b/src/std/rec/boRecord.c
@@ -45,7 +45,7 @@
#define initialize NULL
static long init_record(struct dbCommon *, int);
static long process(struct dbCommon *);
-#define special NULL
+static long special(DBADDR *, int);
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
@@ -136,10 +136,9 @@ static long init_record(struct dbCommon *pcommon,int pass)
long status = 0;
myCallback *pcallback;
- if (pass == 0)
- return 0;
+ if (pass == 0) return 0;
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
if (!pdset) {
recGblRecordError(S_dev_noDSET, prec, "bo: init_record");
@@ -255,7 +254,8 @@ static long process(struct dbCommon *pcommon)
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, NULL);
+
if((prec->val==1) && (prec->high>0)){
myCallback *pcallback;
pcallback = (myCallback *)(prec->rpvt);
@@ -270,7 +270,27 @@ static long process(struct dbCommon *pcommon)
prec->pact=FALSE;
return(status);
}
-
+
+static long special(DBADDR *paddr, int after)
+{
+ boRecord *prec = (boRecord *)(paddr->precord);
+ int special_type = paddr->special;
+
+ switch(special_type) {
+ case(SPC_MOD):
+ if (dbGetFieldIndex(paddr) == boRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return(0);
+ }
+ default:
+ recGblDbaddrError(S_db_badChoice, paddr, "bo: special");
+ return(S_db_badChoice);
+ }
+}
+
#define indexof(field) boRecord##field
static long get_units(DBADDR *paddr, char *units)
@@ -400,30 +420,40 @@ static void monitor(boRecord *prec)
static long writeValue(boRecord *prec)
{
- long status;
- struct bodset *pdset = (struct bodset *) (prec->dset);
+ struct bodset *pdset = (struct bodset *) prec->dset;
+ long status = 0;
- if (prec->pact == TRUE){
- status=(*pdset->write_bo)(prec);
- return(status);
- }
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
- status=dbGetLink(&prec->siml,DBR_USHORT, &prec->simm,0,0);
- if (status)
- return(status);
+ switch (prec->simm) {
+ case menuYesNoNO:
+ status = pdset->write_bo(prec);
+ break;
- if (prec->simm == menuYesNoNO){
- status=(*pdset->write_bo)(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);
+ case menuYesNoYES: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
+ }
- return(status);
+ default:
+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
+ status = -1;
+ }
+
+ return status;
}
diff --git a/src/std/rec/boRecord.dbd b/src/std/rec/boRecord.dbd
index fd002c368..346f0f22c 100644
--- a/src/std/rec/boRecord.dbd
+++ b/src/std/rec/boRecord.dbd
@@ -118,27 +118,54 @@ recordtype(bo) {
interest(3)
}
field(SIOL,DBF_OUTLINK) {
- prompt("Sim Output Specifctn")
+ prompt("Simulation Output Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
- interest(1)
+ special(SPC_MOD)
+ interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
- field(IVOA,DBF_MENU) {
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
+ field(IVOA,DBF_MENU) {
prompt("INVALID outpt action")
promptgroup("50 - Output")
interest(2)
diff --git a/src/std/rec/eventRecord.c b/src/std/rec/eventRecord.c
index 38a4ad62f..dbaef0114 100644
--- a/src/std/rec/eventRecord.c
+++ b/src/std/rec/eventRecord.c
@@ -22,6 +22,7 @@
#include "dbDefs.h"
#include "epicsPrint.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbScan.h"
@@ -97,9 +98,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
struct eventdset *pdset;
long status=0;
- if (pass==0) return(0);
+ if (pass == 0) return 0;
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
recGblInitConstantLink(&prec->siol, DBF_STRING, &prec->sval);
if( (pdset=(struct eventdset *)(prec->dset)) && (pdset->init_record) )
@@ -125,7 +126,7 @@ static long process(struct dbCommon *pcommon)
postEvent(prec->epvt);
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
/* check event list */
monitor(prec);
@@ -142,10 +143,20 @@ static long special(DBADDR *paddr, int after)
{
eventRecord *prec = (eventRecord *)paddr->precord;
+ if (dbGetFieldIndex(paddr) == eventRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return 0;
+ }
+
if (!after) return 0;
+
if (dbGetFieldIndex(paddr) == eventRecordVAL) {
prec->epvt = eventNameToHandle(prec->val);
}
+
return 0;
}
@@ -162,39 +173,47 @@ static void monitor(eventRecord *prec)
static long readValue(eventRecord *prec)
{
- long status;
- struct eventdset *pdset = (struct eventdset *) (prec->dset);
+ struct eventdset *pdset = (struct eventdset *) prec->dset;
+ long status = 0;
- if (prec->pact == TRUE){
- status=(*pdset->read_event)(prec);
- return(status);
- }
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
- status=dbGetLink(&(prec->siml),DBR_USHORT,&(prec->simm),0,0);
+ switch (prec->simm) {
+ case menuYesNoNO:
+ status = pdset->read_event(prec);
+ break;
- if (status)
- return(status);
-
- if (prec->simm == menuYesNoNO){
- status=(*pdset->read_event)(prec);
- return(status);
- }
- if (prec->simm == menuYesNoYES){
- status=dbGetLink(&(prec->siol),DBR_STRING,
- &(prec->sval),0,0);
- if (status==0) {
- if (strcmp(prec->sval, prec->val) != 0) {
- strcpy(prec->val, prec->sval);
- prec->epvt = eventNameToHandle(prec->val);
- }
- prec->udf=FALSE;
+ case menuYesNoYES: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbGetLink(&prec->siol, DBR_STRING, &prec->sval, 0, 0);
+ if (status == 0) {
+ if (strcmp(prec->sval, prec->val) != 0) {
+ strcpy(prec->val, prec->sval);
+ prec->epvt = eventNameToHandle(prec->val);
}
- } else {
- status=-1;
- recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
- return(status);
+ prec->udf = FALSE;
+ }
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
}
- recGblSetSevr(prec,SIMM_ALARM,prec->sims);
+ break;
+ }
- return(status);
+ default:
+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
+ status = -1;
+ }
+
+ return status;
}
diff --git a/src/std/rec/eventRecord.dbd b/src/std/rec/eventRecord.dbd
index 348902e4b..57306f5f5 100644
--- a/src/std/rec/eventRecord.dbd
+++ b/src/std/rec/eventRecord.dbd
@@ -28,7 +28,7 @@ recordtype(event) {
interest(1)
}
field(SIOL,DBF_INLINK) {
- prompt("Sim Input Specifctn")
+ prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
@@ -37,19 +37,46 @@ recordtype(event) {
size(40)
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
- interest(1)
+ special(SPC_MOD)
+ interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
}
diff --git a/src/std/rec/histogramRecord.c b/src/std/rec/histogramRecord.c
index a9563500f..cac81ffd0 100644
--- a/src/std/rec/histogramRecord.c
+++ b/src/std/rec/histogramRecord.c
@@ -182,7 +182,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
wdogInit(prec);
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
recGblInitConstantLink(&prec->siol, DBF_DOUBLE, &prec->sval);
/* must have device support defined */
@@ -228,7 +228,7 @@ static long process(struct dbCommon *pcommon)
return 0;
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
if (status == 0)
add_count(prec);
@@ -246,6 +246,14 @@ static long special(DBADDR *paddr, int after)
{
histogramRecord *prec = (histogramRecord *) paddr->precord;
+ if (paddr->special == SPC_MOD && dbGetFieldIndex(paddr) == histogramRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return 0;
+ }
+
if (!after)
return 0;
@@ -373,33 +381,44 @@ static long clear_histogram(histogramRecord *prec)
static long readValue(histogramRecord *prec)
{
struct histogramdset *pdset = (struct histogramdset *) prec->dset;
- long status;
+ long status = 0;
- if (prec->pact) {
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
+
+ switch (prec->simm) {
+ case menuYesNoNO:
status = pdset->read_histogram(prec);
- return status;
+ break;
+
+ case menuYesNoYES: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbGetLink(&prec->siol, DBR_DOUBLE, &prec->sval, 0, 0);
+ if (status == 0) {
+ prec->sgnl = prec->sval;
+ prec->udf = FALSE;
+ }
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
}
- status = dbGetLink(&prec->siml, DBR_USHORT, &prec->simm, 0, 0);
- if (status)
- return(status);
-
- if (prec->simm == menuYesNoNO) {
- status = pdset->read_histogram(prec);
- return status;
- }
- if (prec->simm == menuYesNoYES) {
- status = dbGetLink(&prec->siol,DBR_DOUBLE, &prec->sval, 0, 0);
- if (status == 0)
- prec->sgnl = prec->sval;
- }
- else {
- status = -1;
+ default:
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
- return status;
+ status = -1;
}
- recGblSetSevr(prec, SIMM_ALARM, prec->sims);
return status;
}
diff --git a/src/std/rec/histogramRecord.dbd b/src/std/rec/histogramRecord.dbd
index 075400fc6..545ae3fcc 100644
--- a/src/std/rec/histogramRecord.dbd
+++ b/src/std/rec/histogramRecord.dbd
@@ -106,7 +106,7 @@ recordtype(histogram) {
interest(1)
}
field(SIOL,DBF_INLINK) {
- prompt("Sim Input Specifctn")
+ prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
@@ -114,22 +114,49 @@ recordtype(histogram) {
prompt("Simulation Value")
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
- interest(1)
+ special(SPC_MOD)
+ interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
- field(HOPR,DBF_ULONG) {
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
+ field(HOPR,DBF_ULONG) {
prompt("High Operating Range")
promptgroup("80 - Display")
interest(1)
diff --git a/src/std/rec/int64inRecord.c b/src/std/rec/int64inRecord.c
index 85063028d..865d05fbb 100644
--- a/src/std/rec/int64inRecord.c
+++ b/src/std/rec/int64inRecord.c
@@ -23,6 +23,7 @@
#include "dbDefs.h"
#include "epicsPrint.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
@@ -30,6 +31,7 @@
#include "errMdef.h"
#include "recSup.h"
#include "recGbl.h"
+#include "special.h"
#include "menuYesNo.h"
#define GEN_SIZE_OFFSET
@@ -44,7 +46,7 @@
#define initialize NULL
static long init_record(dbCommon *, int);
static long process(dbCommon *);
-#define special NULL
+static long special(DBADDR *, int);
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
@@ -100,17 +102,11 @@ static long init_record(dbCommon *pcommon, int pass)
struct int64indset *pdset;
long status;
- if (pass==0) return(0);
+ if (pass == 0) return 0;
- /* int64in.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);
- }
-
- /* int64in.siol must be a CONSTANT or a PV_LINK or a DB_LINK */
- if (prec->siol.type == CONSTANT) {
- recGblInitConstantLink(&prec->siol,DBF_LONG,&prec->sval);
- }
+ /* int64in.siml and .siol must be a CONSTANT or a PV_LINK or a DB_LINK */
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ recGblInitConstantLink(&prec->siol, DBF_INT64, &prec->sval);
if(!(pdset = (struct int64indset *)(prec->dset))) {
recGblRecordError(S_dev_noDSET,(void *)prec,"int64in: init_record");
@@ -150,8 +146,9 @@ static long process(dbCommon *pcommon)
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
- if (status==0) prec->udf = FALSE;
+ recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
+
+ if (status==0) prec->udf = FALSE;
/* check for alarms */
checkAlarms(prec, &timeLast);
@@ -163,7 +160,27 @@ static long process(dbCommon *pcommon)
prec->pact=FALSE;
return(status);
}
-
+
+static long special(DBADDR *paddr, int after)
+{
+ int64inRecord *prec = (int64inRecord *)(paddr->precord);
+ int special_type = paddr->special;
+
+ switch(special_type) {
+ case(SPC_MOD):
+ if (dbGetFieldIndex(paddr) == int64inRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return(0);
+ }
+ default:
+ recGblDbaddrError(S_db_badChoice, paddr, "int64in: special");
+ return(S_db_badChoice);
+ }
+}
+
#define indexof(field) int64inRecord##field
static long get_units(DBADDR *paddr,char *units)
@@ -381,36 +398,44 @@ static void monitor(int64inRecord *prec)
static long readValue(int64inRecord *prec)
{
- long status;
- struct int64indset *pdset = (struct int64indset *) (prec->dset);
+ struct int64indset *pdset = (struct int64indset *) prec->dset;
+ long status = 0;
- if (prec->pact == TRUE){
- status=(*pdset->read_int64in)(prec);
- return(status);
- }
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
- status=dbGetLink(&(prec->siml),DBR_USHORT, &(prec->simm),0,0);
- if (status)
- return(status);
+ switch (prec->simm) {
+ case menuYesNoNO:
+ status = pdset->read_int64in(prec);
+ break;
- if (prec->simm == menuYesNoNO){
- status=(*pdset->read_int64in)(prec);
- return(status);
- }
- if (prec->simm == menuYesNoYES){
- status=dbGetLink(&(prec->siol),DBR_LONG,
- &(prec->sval),0,0);
+ case menuYesNoYES: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbGetLink(&prec->siol, DBR_INT64, &prec->sval, 0, 0);
+ if (status == 0) {
+ prec->val = prec->sval;
+ prec->udf = FALSE;
+ }
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
+ }
- if (status==0) {
- prec->val=prec->sval;
- prec->udf=FALSE;
- }
- } else {
- status=-1;
- recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
- return(status);
- }
- recGblSetSevr(prec,SIMM_ALARM,prec->sims);
+ default:
+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
+ status = -1;
+ }
- return(status);
+ return status;
}
diff --git a/src/std/rec/int64inRecord.dbd.pod b/src/std/rec/int64inRecord.dbd.pod
index b85c68ae0..c85992f05 100644
--- a/src/std/rec/int64inRecord.dbd.pod
+++ b/src/std/rec/int64inRecord.dbd.pod
@@ -265,7 +265,7 @@ simulation mode.
=cut
field(SIOL,DBF_INLINK) {
- prompt("Sim Input Specifctn")
+ prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
@@ -273,21 +273,48 @@ simulation mode.
prompt("Simulation Value")
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
+ special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
}
=head2 Record Support
diff --git a/src/std/rec/int64outRecord.c b/src/std/rec/int64outRecord.c
index ecbe52ce8..da5a76d8f 100644
--- a/src/std/rec/int64outRecord.c
+++ b/src/std/rec/int64outRecord.c
@@ -20,6 +20,7 @@
#include "dbDefs.h"
#include "epicsPrint.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
@@ -27,6 +28,7 @@
#include "errMdef.h"
#include "recSup.h"
#include "recGbl.h"
+#include "special.h"
#include "menuYesNo.h"
#include "menuIvoa.h"
#include "menuOmsl.h"
@@ -41,7 +43,7 @@
#define initialize NULL
static long init_record(dbCommon *, int);
static long process(dbCommon *);
-#define special NULL
+static long special(DBADDR *, int);
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
@@ -98,10 +100,10 @@ static long init_record(dbCommon *pcommon, int pass)
struct int64outdset *pdset;
long status=0;
- if (pass==0) return(0);
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
- }
+ if (pass == 0) return 0;
+
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+
if(!(pdset = (struct int64outdset *)(prec->dset))) {
recGblRecordError(S_dev_noDSET,(void *)prec,"int64out: init_record");
return(S_dev_noDSET);
@@ -180,7 +182,7 @@ static long process(dbCommon *pcommon)
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, NULL);
/* check event list */
monitor(prec);
@@ -192,6 +194,26 @@ static long process(dbCommon *pcommon)
return(status);
}
+static long special(DBADDR *paddr, int after)
+{
+ int64outRecord *prec = (int64outRecord *)(paddr->precord);
+ int special_type = paddr->special;
+
+ switch(special_type) {
+ case(SPC_MOD):
+ if (dbGetFieldIndex(paddr) == int64outRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return(0);
+ }
+ default:
+ recGblDbaddrError(S_db_badChoice, paddr, "int64out: special");
+ return(S_db_badChoice);
+ }
+}
+
#define indexof(field) int64outRecord##field
static long get_units(DBADDR *paddr,char *units)
@@ -352,35 +374,45 @@ static void monitor(int64outRecord *prec)
if (monitor_mask)
db_post_events(prec, &prec->val, monitor_mask);
}
-
+
static long writeValue(int64outRecord *prec)
{
- long status;
- struct int64outdset *pdset = (struct int64outdset *) (prec->dset);
+ struct int64outdset *pdset = (struct int64outdset *) prec->dset;
+ long status = 0;
- if (prec->pact == TRUE){
- status=(*pdset->write_int64out)(prec);
- return(status);
- }
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
- status=dbGetLink(&(prec->siml),DBR_USHORT,&(prec->simm),0,0);
- if (!RTN_SUCCESS(status))
- return(status);
+ switch (prec->simm) {
+ case menuYesNoNO:
+ status = pdset->write_int64out(prec);
+ break;
- if (prec->simm == menuYesNoNO){
- status=(*pdset->write_int64out)(prec);
- return(status);
- }
- if (prec->simm == menuYesNoYES){
- status=dbPutLink(&prec->siol,DBR_INT64,&prec->val,1);
- } else {
- status=-1;
- recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
- return(status);
- }
- recGblSetSevr(prec,SIMM_ALARM,prec->sims);
+ case menuYesNoYES: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbPutLink(&prec->siol, DBR_INT64, &prec->val, 1);
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
+ }
- return(status);
+ default:
+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
+ status = -1;
+ }
+
+ return status;
}
static void convert(int64outRecord *prec, epicsInt64 value)
diff --git a/src/std/rec/int64outRecord.dbd.pod b/src/std/rec/int64outRecord.dbd.pod
index b489ada97..f76541489 100644
--- a/src/std/rec/int64outRecord.dbd.pod
+++ b/src/std/rec/int64outRecord.dbd.pod
@@ -305,26 +305,53 @@ simulation mode.
=cut
field(SIOL,DBF_OUTLINK) {
- prompt("Sim Output Specifctn")
+ prompt("Simulation Output Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
+ special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
=head3 Invalid Alarm Output Action
diff --git a/src/std/rec/longinRecord.c b/src/std/rec/longinRecord.c
index bd3c24ab9..a302a3d29 100644
--- a/src/std/rec/longinRecord.c
+++ b/src/std/rec/longinRecord.c
@@ -23,6 +23,7 @@
#include "dbDefs.h"
#include "epicsPrint.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
@@ -30,6 +31,7 @@
#include "errMdef.h"
#include "recSup.h"
#include "recGbl.h"
+#include "special.h"
#include "menuYesNo.h"
#define GEN_SIZE_OFFSET
@@ -44,7 +46,7 @@
#define initialize NULL
static long init_record(struct dbCommon *, int);
static long process(struct dbCommon *);
-#define special NULL
+static long special(DBADDR *, int);
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
@@ -99,10 +101,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
struct longinRecord *prec = (struct longinRecord *)pcommon;
struct longindset *pdset = (struct longindset *) prec->dset;
- if (pass==0)
- return(0);
+ if (pass == 0) return 0;
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
recGblInitConstantLink(&prec->siol, DBF_LONG, &prec->sval);
if (!pdset) {
@@ -149,8 +150,9 @@ static long process(struct dbCommon *pcommon)
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
- if (status==0) prec->udf = FALSE;
+ recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
+
+ if (status==0) prec->udf = FALSE;
/* check for alarms */
checkAlarms(prec, &timeLast);
@@ -163,6 +165,26 @@ static long process(struct dbCommon *pcommon)
return(status);
}
+static long special(DBADDR *paddr, int after)
+{
+ longinRecord *prec = (longinRecord *)(paddr->precord);
+ int special_type = paddr->special;
+
+ switch(special_type) {
+ case(SPC_MOD):
+ if (dbGetFieldIndex(paddr) == longinRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return(0);
+ }
+ default:
+ recGblDbaddrError(S_db_badChoice, paddr, "longin: special");
+ return(S_db_badChoice);
+ }
+}
+
#define indexof(field) longinRecord##field
static long get_units(DBADDR *paddr,char *units)
@@ -380,36 +402,44 @@ static void monitor(longinRecord *prec)
static long readValue(longinRecord *prec)
{
- long status;
- struct longindset *pdset = (struct longindset *) (prec->dset);
+ struct longindset *pdset = (struct longindset *) prec->dset;
+ long status = 0;
- if (prec->pact == TRUE){
- status=(*pdset->read_longin)(prec);
- return(status);
- }
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
- status=dbGetLink(&(prec->siml),DBR_USHORT, &(prec->simm),0,0);
- if (status)
- return(status);
+ switch (prec->simm) {
+ case menuYesNoNO:
+ status = pdset->read_longin(prec);
+ break;
- if (prec->simm == menuYesNoNO){
- status=(*pdset->read_longin)(prec);
- return(status);
- }
- if (prec->simm == menuYesNoYES){
- status=dbGetLink(&(prec->siol),DBR_LONG,
- &(prec->sval),0,0);
+ case menuYesNoYES: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbGetLink(&prec->siol, DBR_LONG, &prec->sval, 0, 0);
+ if (status == 0) {
+ prec->val = prec->sval;
+ prec->udf = FALSE;
+ }
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
+ }
- if (status==0) {
- prec->val=prec->sval;
- prec->udf=FALSE;
- }
- } else {
- status=-1;
- recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
- return(status);
- }
- recGblSetSevr(prec,SIMM_ALARM,prec->sims);
+ default:
+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
+ status = -1;
+ }
- return(status);
+ return status;
}
diff --git a/src/std/rec/longinRecord.dbd b/src/std/rec/longinRecord.dbd
index 60eee5000..f0e5a8de5 100644
--- a/src/std/rec/longinRecord.dbd
+++ b/src/std/rec/longinRecord.dbd
@@ -135,7 +135,7 @@ recordtype(longin) {
interest(3)
}
field(SIOL,DBF_INLINK) {
- prompt("Sim Input Specifctn")
+ prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
@@ -143,19 +143,46 @@ recordtype(longin) {
prompt("Simulation Value")
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
- interest(1)
+ special(SPC_MOD)
+ interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
}
diff --git a/src/std/rec/longoutRecord.c b/src/std/rec/longoutRecord.c
index 6062ad741..0b1d66d50 100644
--- a/src/std/rec/longoutRecord.c
+++ b/src/std/rec/longoutRecord.c
@@ -20,6 +20,7 @@
#include "dbDefs.h"
#include "epicsPrint.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
@@ -27,6 +28,7 @@
#include "errMdef.h"
#include "recSup.h"
#include "recGbl.h"
+#include "special.h"
#include "menuYesNo.h"
#include "menuIvoa.h"
#include "menuOmsl.h"
@@ -41,7 +43,7 @@
#define initialize NULL
static long init_record(struct dbCommon *, int);
static long process(struct dbCommon *);
-#define special NULL
+static long special(DBADDR *, int);
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
@@ -96,10 +98,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
struct longoutRecord *prec = (struct longoutRecord *)pcommon;
struct longoutdset *pdset = (struct longoutdset *) prec->dset;
- if (pass==0)
- return 0;
+ if (pass == 0) return 0;
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
if (!pdset) {
recGblRecordError(S_dev_noDSET, prec, "longout: init_record");
@@ -183,7 +184,7 @@ static long process(struct dbCommon *pcommon)
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, NULL);
/* check event list */
monitor(prec);
@@ -195,6 +196,26 @@ static long process(struct dbCommon *pcommon)
return(status);
}
+static long special(DBADDR *paddr, int after)
+{
+ longoutRecord *prec = (longoutRecord *)(paddr->precord);
+ int special_type = paddr->special;
+
+ switch(special_type) {
+ case(SPC_MOD):
+ if (dbGetFieldIndex(paddr) == longoutRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return(0);
+ }
+ default:
+ recGblDbaddrError(S_db_badChoice, paddr, "longout: special");
+ return(S_db_badChoice);
+ }
+}
+
#define indexof(field) longoutRecord##field
static long get_units(DBADDR *paddr,char *units)
@@ -358,32 +379,42 @@ static void monitor(longoutRecord *prec)
static long writeValue(longoutRecord *prec)
{
- long status;
- struct longoutdset *pdset = (struct longoutdset *) (prec->dset);
+ struct longoutdset *pdset = (struct longoutdset *) prec->dset;
+ long status = 0;
- if (prec->pact == TRUE){
- status=(*pdset->write_longout)(prec);
- return(status);
- }
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
- status=dbGetLink(&(prec->siml),DBR_USHORT,&(prec->simm),0,0);
- if (!RTN_SUCCESS(status))
- return(status);
+ switch (prec->simm) {
+ case menuYesNoNO:
+ status = pdset->write_longout(prec);
+ break;
- if (prec->simm == menuYesNoNO){
- status=(*pdset->write_longout)(prec);
- return(status);
- }
- if (prec->simm == menuYesNoYES){
- status=dbPutLink(&prec->siol,DBR_LONG,&prec->val,1);
- } else {
- status=-1;
- recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
- return(status);
- }
- recGblSetSevr(prec,SIMM_ALARM,prec->sims);
+ case menuYesNoYES: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbPutLink(&prec->siol, DBR_LONG, &prec->val, 1);
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
+ }
- return(status);
+ default:
+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
+ status = -1;
+ }
+
+ return status;
}
static void convert(longoutRecord *prec, epicsInt32 value)
diff --git a/src/std/rec/longoutRecord.dbd b/src/std/rec/longoutRecord.dbd
index c3ba0b977..626be1645 100644
--- a/src/std/rec/longoutRecord.dbd
+++ b/src/std/rec/longoutRecord.dbd
@@ -150,27 +150,54 @@ recordtype(longout) {
interest(3)
}
field(SIOL,DBF_OUTLINK) {
- prompt("Sim Output Specifctn")
+ prompt("Simulation Output Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
- interest(1)
+ special(SPC_MOD)
+ interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
- field(IVOA,DBF_MENU) {
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
+ field(IVOA,DBF_MENU) {
prompt("INVALID output action")
promptgroup("50 - Output")
interest(2)
diff --git a/src/std/rec/lsiRecord.c b/src/std/rec/lsiRecord.c
index 81b6785ab..261313f07 100644
--- a/src/std/rec/lsiRecord.c
+++ b/src/std/rec/lsiRecord.c
@@ -18,6 +18,7 @@
#include "dbDefs.h"
#include "errlog.h"
#include "alarm.h"
+#include "callback.h"
#include "cantProceed.h"
#include "dbAccess.h"
#include "dbEvent.h"
@@ -56,7 +57,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
return 0;
}
- dbLoadLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
pdset = (lsidset *) prec->dset;
if (!pdset) {
@@ -104,7 +105,7 @@ static long process(struct dbCommon *pcommon)
return 0;
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
monitor(prec);
@@ -171,6 +172,15 @@ static long put_array_info(DBADDR *paddr, long nNew)
static long special(DBADDR *paddr, int after)
{
lsiRecord *prec = (lsiRecord *) paddr->precord;
+ int special_type = paddr->special;
+
+ if (special_type == SPC_MOD && dbGetFieldIndex(paddr) == lsiRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return 0;
+ }
if (!after)
return 0;
@@ -211,40 +221,46 @@ static void monitor(lsiRecord *prec)
static long readValue(lsiRecord *prec)
{
- long status;
- lsidset *pdset = (lsidset *) prec->dset;
+ struct lsidset *pdset = (struct lsidset *) prec->dset;
+ long status = 0;
- if (prec->pact)
- goto read;
-
- status = dbGetLink(&prec->siml, DBR_USHORT, &prec->simm, 0, 0);
- if (status)
- return status;
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
switch (prec->simm) {
case menuYesNoNO:
-read:
status = pdset->read_string(prec);
break;
- case menuYesNoYES:
+ case menuYesNoYES: {
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
- status = dbGetLinkLS(&prec->siol, prec->val, prec->sizv, &prec->len);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbGetLinkLS(&prec->siol, prec->val, prec->sizv, &prec->len);
+ if (status == 0) prec->udf = FALSE;
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
break;
+ }
default:
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
status = -1;
}
- if (!status)
- prec->udf = FALSE;
-
return status;
}
-
-/* Create Record Support Entry Table*/
+/* Create Record Support Entry Table */
#define report NULL
#define initialize NULL
diff --git a/src/std/rec/lsiRecord.dbd b/src/std/rec/lsiRecord.dbd
index c50d905d8..689366f98 100644
--- a/src/std/rec/lsiRecord.dbd
+++ b/src/std/rec/lsiRecord.dbd
@@ -67,11 +67,12 @@ recordtype(lsi) {
field(SIML,DBF_INLINK) {
prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
- interest(2)
+ interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
- interest(2)
+ special(SPC_MOD)
+ interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
@@ -81,8 +82,34 @@ recordtype(lsi) {
menu(menuAlarmSevr)
}
field(SIOL,DBF_INLINK) {
- prompt("Sim Input Specifctn")
+ prompt("Simulation Input Link")
+ promptgroup("90 - Simulate")
+ interest(1)
+ }
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
promptgroup("90 - Simulate")
interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
}
}
diff --git a/src/std/rec/lsoRecord.c b/src/std/rec/lsoRecord.c
index 625f5d77c..dcbe1500c 100644
--- a/src/std/rec/lsoRecord.c
+++ b/src/std/rec/lsoRecord.c
@@ -19,6 +19,7 @@
#include "dbDefs.h"
#include "errlog.h"
#include "alarm.h"
+#include "callback.h"
#include "cantProceed.h"
#include "dbAccess.h"
#include "dbEvent.h"
@@ -60,7 +61,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
return 0;
}
- dbLoadLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
pdset = (lsodset *) prec->dset;
if (!pdset) {
@@ -146,7 +147,7 @@ static long process(struct dbCommon *pcommon)
return status;
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, NULL);
monitor(prec);
@@ -213,6 +214,15 @@ static long put_array_info(DBADDR *paddr, long nNew)
static long special(DBADDR *paddr, int after)
{
lsoRecord *prec = (lsoRecord *) paddr->precord;
+ int special_type = paddr->special;
+
+ if (special_type == SPC_MOD && dbGetFieldIndex(paddr) == lsoRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return 0;
+ }
if (!after)
return 0;
@@ -253,26 +263,35 @@ static void monitor(lsoRecord *prec)
static long writeValue(lsoRecord *prec)
{
- long status;
lsodset *pdset = (lsodset *) prec->dset;
+ long status = 0;
- if (prec->pact)
- goto write;
-
- status = dbGetLink(&prec->siml, DBR_USHORT, &prec->simm, 0, 0);
- if (status)
- return(status);
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
switch (prec->simm) {
case menuYesNoNO:
-write:
status = pdset->write_string(prec);
break;
- case menuYesNoYES:
+ case menuYesNoYES: {
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
- status = dbPutLink(&prec->siol,DBR_STRING, prec->val,1);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbPutLinkLS(&prec->siol, prec->val, prec->len);
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
break;
+ }
default:
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
diff --git a/src/std/rec/lsoRecord.dbd b/src/std/rec/lsoRecord.dbd
index 69203f2d0..8d3a64edc 100644
--- a/src/std/rec/lsoRecord.dbd
+++ b/src/std/rec/lsoRecord.dbd
@@ -89,24 +89,51 @@ recordtype(lso) {
menu(menuPost)
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode link")
+ prompt("Simulation Mode link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
+ special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_OUTLINK) {
- prompt("Sim Output Specifctn")
+ prompt("Simulation Output Link")
promptgroup("90 - Simulate")
interest(1)
}
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
}
diff --git a/src/std/rec/mbbiDirectRecord.c b/src/std/rec/mbbiDirectRecord.c
index 112272925..566bbe21d 100644
--- a/src/std/rec/mbbiDirectRecord.c
+++ b/src/std/rec/mbbiDirectRecord.c
@@ -24,6 +24,7 @@
#include "dbDefs.h"
#include "errlog.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
@@ -44,7 +45,7 @@
#define initialize NULL
static long init_record(struct dbCommon *, int);
static long process(struct dbCommon *);
-#define special NULL
+static long special(DBADDR *, int);
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
@@ -100,8 +101,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
struct mbbidset *pdset = (struct mbbidset *) prec->dset;
long status = 0;
- if (pass == 0)
- return status;
+ if (pass == 0) return 0;
if (!pdset) {
recGblRecordError(S_dev_noDSET, prec, "mbbiDirect: init_record");
@@ -113,7 +113,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
return S_dev_missingSup;
}
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
recGblInitConstantLink(&prec->siol, DBF_USHORT, &prec->sval);
/* Initialize MASK if the user set NOBT instead */
@@ -158,7 +158,7 @@ static long process(struct dbCommon *pcommon)
return 0;
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
if (status == 0) {
/* Convert RVAL to VAL */
@@ -184,6 +184,26 @@ static long process(struct dbCommon *pcommon)
return status;
}
+static long special(DBADDR *paddr, int after)
+{
+ mbbiDirectRecord *prec = (mbbiDirectRecord *)(paddr->precord);
+ int special_type = paddr->special;
+
+ switch(special_type) {
+ case(SPC_MOD):
+ if (dbGetFieldIndex(paddr) == mbbiDirectRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return(0);
+ }
+ default:
+ recGblDbaddrError(S_db_badChoice, paddr, "mbbiDirect: special");
+ return(S_db_badChoice);
+ }
+}
+
static void monitor(mbbiDirectRecord *prec)
{
epicsUInt16 events = recGblResetAlarms(prec);
@@ -219,42 +239,49 @@ static void monitor(mbbiDirectRecord *prec)
static long readValue(mbbiDirectRecord *prec)
{
struct mbbidset *pdset = (struct mbbidset *) prec->dset;
- long status;
+ long status = 0;
- if (prec->pact)
- return pdset->read_mbbi(prec);
-
- status = dbGetLink(&prec->siml, DBR_ENUM, &prec->simm, 0, 0);
- if (status)
- return status;
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
switch (prec->simm) {
case menuSimmNO:
- return pdset->read_mbbi(prec);
+ status = pdset->read_mbbi(prec);
+ break;
case menuSimmYES:
- status = dbGetLink(&prec->siol, DBR_ULONG, &prec->sval, 0, 0);
- if (status == 0) {
- prec->val = prec->sval;
- prec->udf = FALSE;
+ case menuSimmRAW: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbGetLink(&prec->siol, DBR_ULONG, &prec->sval, 0, 0);
+ if (status == 0) {
+ if (prec->simm == menuSimmYES) {
+ prec->val = prec->sval;
+ status = 2; /* Don't convert */
+ } else {
+ prec->rval = prec->sval;
+ }
+ prec->udf = FALSE;
+ }
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
}
- 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;
+ status = -1;
}
- recGblSetSevr(prec, SIMM_ALARM, prec->sims);
return status;
}
diff --git a/src/std/rec/mbbiDirectRecord.dbd b/src/std/rec/mbbiDirectRecord.dbd
index 3fa3d8823..c7ca0f466 100644
--- a/src/std/rec/mbbiDirectRecord.dbd
+++ b/src/std/rec/mbbiDirectRecord.dbd
@@ -50,7 +50,7 @@ recordtype(mbbiDirect) {
interest(1)
}
field(SIOL,DBF_INLINK) {
- prompt("Sim Input Specifctn")
+ prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
@@ -58,21 +58,48 @@ recordtype(mbbiDirect) {
prompt("Simulation Value")
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
+ special(SPC_MOD)
interest(1)
menu(menuSimm)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
field(B0,DBF_UCHAR) {
prompt("Bit 0")
pp(TRUE)
diff --git a/src/std/rec/mbbiRecord.c b/src/std/rec/mbbiRecord.c
index ad5a8ce06..d04161d56 100644
--- a/src/std/rec/mbbiRecord.c
+++ b/src/std/rec/mbbiRecord.c
@@ -22,6 +22,7 @@
#include "dbDefs.h"
#include "epicsPrint.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
@@ -46,7 +47,7 @@
#define initialize NULL
static long init_record(struct dbCommon *, int);
static long process(struct dbCommon *);
-static long special(DBADDR *, int);
+static long special(DBADDR *, int);
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
@@ -117,8 +118,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
struct mbbidset *pdset = (struct mbbidset *) prec->dset;
long status = 0;
- if (pass == 0)
- return 0;
+ if (pass == 0) return 0;
pdset = (struct mbbidset *) prec->dset;
if (!pdset) {
@@ -131,7 +131,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
return S_dev_missingSup;
}
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
recGblInitConstantLink(&prec->siol, DBF_USHORT, &prec->sval);
/* Initialize MASK if the user set NOBT instead */
@@ -172,7 +172,7 @@ static long process(struct dbCommon *pcommon)
return 0;
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
if (status == 0) {
/* Convert RVAL to VAL */
@@ -215,20 +215,25 @@ static long special(DBADDR *paddr, int after)
mbbiRecord *prec = (mbbiRecord *) paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
- if (!after)
- return 0;
-
switch (paddr->special) {
case SPC_MOD:
- init_common(prec);
if (fieldIndex >= mbbiRecordZRST && fieldIndex <= mbbiRecordFFST) {
int event = DBE_PROPERTY;
+ if (!after) return 0;
+ init_common(prec);
if (prec->val == fieldIndex - mbbiRecordZRST)
event |= DBE_VALUE | DBE_LOG;
db_post_events(prec, &prec->val, event);
+ return 0;
+ }
+ if (fieldIndex == mbbiRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return 0;
}
- return 0;
default:
recGblDbaddrError(S_db_badChoice, paddr, "mbbi: special");
return S_db_badChoice;
@@ -372,42 +377,49 @@ static void monitor(mbbiRecord *prec)
static long readValue(mbbiRecord *prec)
{
struct mbbidset *pdset = (struct mbbidset *) prec->dset;
- long status;
+ long status = 0;
- if (prec->pact)
- return pdset->read_mbbi(prec);
-
- status = dbGetLink(&prec->siml, DBR_ENUM, &prec->simm, 0, 0);
- if (status)
- return status;
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
switch (prec->simm) {
case menuSimmNO:
- return pdset->read_mbbi(prec);
+ status = pdset->read_mbbi(prec);
+ break;
case menuSimmYES:
- status = dbGetLink(&prec->siol, DBR_ULONG, &prec->sval, 0, 0);
- if (status == 0) {
- prec->val = prec->sval;
- prec->udf = FALSE;
+ case menuSimmRAW: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbGetLink(&prec->siol, DBR_ULONG, &prec->sval, 0, 0);
+ if (status == 0) {
+ if (prec->simm == menuSimmYES) {
+ prec->val = prec->sval;
+ status = 2; /* Don't convert */
+ } else {
+ prec->rval = prec->sval;
+ }
+ prec->udf = FALSE;
+ }
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
}
- 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;
+ status = -1;
}
- recGblSetSevr(prec, SIMM_ALARM, prec->sims);
return status;
}
diff --git a/src/std/rec/mbbiRecord.dbd b/src/std/rec/mbbiRecord.dbd
index 1f5724c92..52f18e43d 100644
--- a/src/std/rec/mbbiRecord.dbd
+++ b/src/std/rec/mbbiRecord.dbd
@@ -452,7 +452,7 @@ recordtype(mbbi) {
interest(1)
}
field(SIOL,DBF_INLINK) {
- prompt("Sim Input Specifctn")
+ prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
@@ -460,19 +460,46 @@ recordtype(mbbi) {
prompt("Simulation Value")
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
+ special(SPC_MOD)
interest(1)
menu(menuSimm)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
}
diff --git a/src/std/rec/mbboDirectRecord.c b/src/std/rec/mbboDirectRecord.c
index 0a6e3391e..750228bc9 100644
--- a/src/std/rec/mbboDirectRecord.c
+++ b/src/std/rec/mbboDirectRecord.c
@@ -22,6 +22,7 @@
#include "dbDefs.h"
#include "errlog.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
@@ -102,8 +103,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
struct mbbodset *pdset = (struct mbbodset *) prec->dset;
long status = 0;
- if (pass == 0)
- return 0;
+ if (pass == 0) return 0;
if (!pdset) {
recGblRecordError(S_dev_noDSET, prec, "mbboDirect: init_record");
@@ -115,7 +115,8 @@ static long init_record(struct dbCommon *pcommon, int pass)
return S_dev_missingSup;
}
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+
if (recGblInitConstantLink(&prec->dol, DBF_USHORT, &prec->val))
prec->udf = FALSE;
@@ -232,7 +233,8 @@ CONTINUE:
return 0;
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, NULL);
+
monitor(prec);
/* Wrap up */
@@ -244,6 +246,15 @@ CONTINUE:
static long special(DBADDR *paddr, int after)
{
mbboDirectRecord *prec = (mbboDirectRecord *) paddr->precord;
+ int fieldIndex = dbGetFieldIndex(paddr);
+
+ if (paddr->special == SPC_MOD && fieldIndex == mbboDirectRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return 0;
+ }
if (!after)
return 0;
@@ -335,26 +346,40 @@ static void convert(mbboDirectRecord *prec)
static long writeValue(mbboDirectRecord *prec)
{
- long status;
struct mbbodset *pdset = (struct mbbodset *) prec->dset;
+ long status = 0;
- if (prec->pact)
- return pdset->write_mbbo(prec);
-
- status = dbGetLink(&prec->siml, DBR_ENUM, &prec->simm, 0, 0);
- if (status)
- return status;
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
switch (prec->simm) {
case menuYesNoNO:
- return pdset->write_mbbo(prec);
+ status = pdset->write_mbbo(prec);
+ break;
- case menuYesNoYES:
+ case menuYesNoYES: {
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
- return dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
+ }
default:
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
- return -1;
+ status = -1;
}
+
+ return status;
}
diff --git a/src/std/rec/mbboDirectRecord.dbd b/src/std/rec/mbboDirectRecord.dbd
index 0b4285e32..241199d9e 100644
--- a/src/std/rec/mbboDirectRecord.dbd
+++ b/src/std/rec/mbboDirectRecord.dbd
@@ -185,26 +185,53 @@ recordtype(mbboDirect) {
interest(1)
}
field(SIOL,DBF_OUTLINK) {
- prompt("Sim Output Specifctn")
+ prompt("Simulation Output Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
+ special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
field(IVOA,DBF_MENU) {
prompt("INVALID outpt action")
promptgroup("50 - Output")
diff --git a/src/std/rec/mbboRecord.c b/src/std/rec/mbboRecord.c
index 0ae6a815a..2e2a35bb2 100644
--- a/src/std/rec/mbboRecord.c
+++ b/src/std/rec/mbboRecord.c
@@ -23,6 +23,7 @@
#include "dbDefs.h"
#include "epicsPrint.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
@@ -135,7 +136,8 @@ static long init_record(struct dbCommon *pcommon, int pass)
return S_dev_missingSup;
}
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+
if (recGblInitConstantLink(&prec->dol, DBF_USHORT, &prec->val))
prec->udf = FALSE;
@@ -254,7 +256,8 @@ CONTINUE:
return 0;
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, NULL);
+
monitor(prec);
/* Wrap up */
@@ -268,20 +271,25 @@ static long special(DBADDR *paddr, int after)
mbboRecord *prec = (mbboRecord *) paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
- if (!after)
- return 0;
-
switch (paddr->special) {
case SPC_MOD:
- init_common(prec);
if (fieldIndex >= mbboRecordZRST && fieldIndex <= mbboRecordFFST) {
int event = DBE_PROPERTY;
+ if (!after) return 0;
+ init_common(prec);
if (prec->val == fieldIndex - mbboRecordZRST)
event |= DBE_VALUE | DBE_LOG;
db_post_events(prec, &prec->val, event);
+ return 0;
+ }
+ if (fieldIndex == mbboRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return 0;
}
- return 0;
default:
recGblDbaddrError(S_db_badChoice, paddr, "mbbo: special");
return S_db_badChoice;
@@ -427,26 +435,40 @@ static void convert(mbboRecord *prec)
static long writeValue(mbboRecord *prec)
{
- long status;
struct mbbodset *pdset = (struct mbbodset *) prec->dset;
+ long status = 0;
- if (prec->pact)
- return pdset->write_mbbo(prec);
-
- status = dbGetLink(&prec->siml, DBR_USHORT, &prec->simm, 0, 0);
- if (status)
- return status;
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
switch (prec->simm) {
case menuYesNoNO:
- return pdset->write_mbbo(prec);
+ status = pdset->write_mbbo(prec);
+ break;
- case menuYesNoYES:
+ case menuYesNoYES: {
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
- return dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
+ }
default:
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
- return -1;
+ status = -1;
}
+
+ return status;
}
diff --git a/src/std/rec/mbboRecord.dbd b/src/std/rec/mbboRecord.dbd
index f841ba018..5475029df 100644
--- a/src/std/rec/mbboRecord.dbd
+++ b/src/std/rec/mbboRecord.dbd
@@ -465,27 +465,54 @@ recordtype(mbbo) {
interest(1)
}
field(SIOL,DBF_OUTLINK) {
- prompt("Sim Output Specifctn")
+ prompt("Simulation Output Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
- interest(1)
+ special(SPC_MOD)
+ interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
- field(IVOA,DBF_MENU) {
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
+ field(IVOA,DBF_MENU) {
prompt("INVALID outpt action")
promptgroup("50 - Output")
interest(2)
diff --git a/src/std/rec/stringinRecord.c b/src/std/rec/stringinRecord.c
index 163b23a49..212e79378 100644
--- a/src/std/rec/stringinRecord.c
+++ b/src/std/rec/stringinRecord.c
@@ -23,6 +23,7 @@
#include "dbDefs.h"
#include "epicsPrint.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
@@ -30,6 +31,7 @@
#include "errMdef.h"
#include "recSup.h"
#include "recGbl.h"
+#include "special.h"
#include "menuYesNo.h"
#define GEN_SIZE_OFFSET
@@ -42,7 +44,7 @@
#define initialize NULL
static long init_record(struct dbCommon *, int);
static long process(struct dbCommon *);
-#define special NULL
+static long special(DBADDR *, int);
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
@@ -96,10 +98,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
STATIC_ASSERT(sizeof(prec->oval)==sizeof(prec->val));
struct stringindset *pdset = (struct stringindset *) prec->dset;
- if (pass==0)
- return 0;
+ if (pass == 0) return 0;
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
recGblInitConstantLink(&prec->siol, DBF_STRING, prec->sval);
if (!pdset) {
@@ -141,9 +142,9 @@ static long process(struct dbCommon *pcommon)
status=readValue(prec); /* read the new value */
/* check if device support set pact */
if ( !pact && prec->pact ) return(0);
- prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ prec->pact = TRUE;
+ recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
/* check event list */
monitor(prec);
@@ -154,6 +155,26 @@ static long process(struct dbCommon *pcommon)
return(status);
}
+static long special(DBADDR *paddr, int after)
+{
+ stringinRecord *prec = (stringinRecord *)(paddr->precord);
+ int special_type = paddr->special;
+
+ switch(special_type) {
+ case(SPC_MOD):
+ if (dbGetFieldIndex(paddr) == stringinRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return(0);
+ }
+ default:
+ recGblDbaddrError(S_db_badChoice, paddr, "stringin: special");
+ return(S_db_badChoice);
+ }
+}
+
static void monitor(stringinRecord *prec)
{
int monitor_mask = recGblResetAlarms(prec);
@@ -174,35 +195,44 @@ static void monitor(stringinRecord *prec)
static long readValue(stringinRecord *prec)
{
- long status;
- struct stringindset *pdset = (struct stringindset *) (prec->dset);
+ struct stringindset *pdset = (struct stringindset *) prec->dset;
+ long status = 0;
- if (prec->pact == TRUE){
- status=(*pdset->read_stringin)(prec);
- return(status);
- }
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
- status=dbGetLink(&(prec->siml),DBR_USHORT, &(prec->simm),0,0);
- if (status)
- return(status);
+ switch (prec->simm) {
+ case menuYesNoNO:
+ status = pdset->read_stringin(prec);
+ break;
- if (prec->simm == menuYesNoNO){
- status=(*pdset->read_stringin)(prec);
- return(status);
- }
- if (prec->simm == menuYesNoYES){
- status=dbGetLink(&(prec->siol),DBR_STRING,
- prec->sval,0,0);
- if (status==0) {
- strcpy(prec->val,prec->sval);
- prec->udf=FALSE;
- }
- } else {
- status=-1;
- recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
- return(status);
- }
- recGblSetSevr(prec,SIMM_ALARM,prec->sims);
+ case menuYesNoYES: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbGetLink(&prec->siol, DBR_STRING, prec->sval, 0, 0);
+ if (status == 0) {
+ strcpy(prec->val, prec->sval);
+ prec->udf = FALSE;
+ }
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
+ }
- return(status);
+ default:
+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
+ status = -1;
+ }
+
+ return status;
}
diff --git a/src/std/rec/stringinRecord.dbd b/src/std/rec/stringinRecord.dbd
index 5b0b76813..ec7b2d570 100644
--- a/src/std/rec/stringinRecord.dbd
+++ b/src/std/rec/stringinRecord.dbd
@@ -43,7 +43,7 @@ recordtype(stringin) {
menu(stringinPOST)
}
field(SIOL,DBF_INLINK) {
- prompt("Sim Input Specifctn")
+ prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
@@ -53,19 +53,46 @@ recordtype(stringin) {
size(40)
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
- interest(1)
+ special(SPC_MOD)
+ interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
}
diff --git a/src/std/rec/stringoutRecord.c b/src/std/rec/stringoutRecord.c
index 416a6db5e..fedc9fc68 100644
--- a/src/std/rec/stringoutRecord.c
+++ b/src/std/rec/stringoutRecord.c
@@ -23,6 +23,7 @@
#include "dbDefs.h"
#include "epicsPrint.h"
#include "alarm.h"
+#include "callback.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
@@ -30,6 +31,7 @@
#include "errMdef.h"
#include "recSup.h"
#include "recGbl.h"
+#include "special.h"
#include "menuOmsl.h"
#include "menuIvoa.h"
#include "menuYesNo.h"
@@ -44,7 +46,7 @@
#define initialize NULL
static long init_record(struct dbCommon *, int);
static long process(struct dbCommon *);
-#define special NULL
+static long special(DBADDR *, int);
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
@@ -98,10 +100,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
STATIC_ASSERT(sizeof(prec->oval)==sizeof(prec->val));
struct stringoutdset *pdset = (struct stringoutdset *) prec->dset;
- if (pass==0)
- return 0;
+ if (pass == 0) return 0;
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
if (!pdset) {
recGblRecordError(S_dev_noDSET, prec, "stringout: init_record");
@@ -179,13 +180,34 @@ static long process(struct dbCommon *pcommon)
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
- recGblGetTimeStamp(prec);
+ recGblGetTimeStampSimm(prec, prec->simm, NULL);
+
monitor(prec);
recGblFwdLink(prec);
prec->pact=FALSE;
return(status);
}
-
+
+static long special(DBADDR *paddr, int after)
+{
+ stringoutRecord *prec = (stringoutRecord *)(paddr->precord);
+ int special_type = paddr->special;
+
+ switch(special_type) {
+ case(SPC_MOD):
+ if (dbGetFieldIndex(paddr) == stringoutRecordSIMM) {
+ if (!after)
+ recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
+ else
+ recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
+ return 0;
+ }
+ default:
+ recGblDbaddrError(S_db_badChoice, paddr, "stringout: special");
+ return(S_db_badChoice);
+ }
+}
+
static void monitor(stringoutRecord *prec)
{
int monitor_mask = recGblResetAlarms(prec);
@@ -206,32 +228,40 @@ static void monitor(stringoutRecord *prec)
static long writeValue(stringoutRecord *prec)
{
- long status;
- struct stringoutdset *pdset = (struct stringoutdset *) (prec->dset);
+ struct stringoutdset *pdset = (struct stringoutdset *) prec->dset;
+ long status = 0;
- if (prec->pact == TRUE){
- status=(*pdset->write_stringout)(prec);
- return(status);
- }
+ if (!prec->pact) {
+ status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
+ if (status) return status;
+ }
- status=dbGetLink(&(prec->siml),DBR_USHORT,
- &(prec->simm),0,0);
- if (status)
- return(status);
+ switch (prec->simm) {
+ case menuYesNoNO:
+ status = pdset->write_stringout(prec);
+ break;
- if (prec->simm == menuYesNoNO){
- status=(*pdset->write_stringout)(prec);
- return(status);
- }
- if (prec->simm == menuYesNoYES){
- status=dbPutLink(&prec->siol,DBR_STRING,
- prec->val,1);
- } else {
- status=-1;
- recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
- return(status);
- }
- recGblSetSevr(prec,SIMM_ALARM,prec->sims);
+ case menuYesNoYES: {
+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
+ if (prec->pact || (prec->sdly < 0.)) {
+ status = dbPutLink(&prec->siol, DBR_STRING, &prec->val, 1);
+ prec->pact = FALSE;
+ } else { /* !prec->pact && delay >= 0. */
+ CALLBACK *pvt = prec->simpvt;
+ if (!pvt) {
+ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
+ prec->simpvt = pvt;
+ }
+ if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
+ prec->pact = TRUE;
+ }
+ break;
+ }
- return(status);
+ default:
+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
+ status = -1;
+ }
+
+ return status;
}
diff --git a/src/std/rec/stringoutRecord.dbd b/src/std/rec/stringoutRecord.dbd
index fe0bae5d0..358340c6d 100644
--- a/src/std/rec/stringoutRecord.dbd
+++ b/src/std/rec/stringoutRecord.dbd
@@ -54,27 +54,54 @@ recordtype(stringout) {
menu(stringoutPOST)
}
field(SIOL,DBF_OUTLINK) {
- prompt("Sim Output Specifctn")
+ prompt("Simulation Output Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIML,DBF_INLINK) {
- prompt("Sim Mode Location")
+ prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
+ special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
- prompt("Sim mode Alarm Svrty")
+ prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
- field(IVOA,DBF_MENU) {
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
+ field(IVOA,DBF_MENU) {
prompt("INVALID output action")
promptgroup("50 - Output")
interest(2)
diff --git a/src/std/rec/test/Makefile b/src/std/rec/test/Makefile
index 5a591b230..129c6e91f 100644
--- a/src/std/rec/test/Makefile
+++ b/src/std/rec/test/Makefile
@@ -104,6 +104,19 @@ regressTest_SRCS += regressTest_registerRecordDeviceDriver.cpp
TESTFILES += $(COMMON_DIR)/regressTest.dbd ../regressArray1.db ../regressHex.db ../regressLinkMS.db
TESTS += regressTest
+TARGETS += $(COMMON_DIR)/simmTest.dbd
+TARGETS += $(COMMON_DIR)/simmTest.db
+DBDDEPENDS_FILES += simmTest.dbd$(DEP)
+DBDDEPENDS_FILES += simmTest.db$(DEP)
+simmTest_DBD += base.dbd
+TESTPROD_HOST += simmTest
+simmTest_SRCS += simmTest.c
+simmTest_SRCS += simmTest_registerRecordDeviceDriver.cpp
+testHarness_SRCS += simmTest.c
+testHarness_SRCS += simmTest_registerRecordDeviceDriver.cpp
+TESTFILES += $(COMMON_DIR)/simmTest.dbd $(COMMON_DIR)/simmTest.db
+TESTS += simmTest
+
# epicsRunRecordTests runs all the test programs in a known working order.
testHarness_SRCS += epicsRunRecordTests.c
diff --git a/src/std/rec/test/epicsRunRecordTests.c b/src/std/rec/test/epicsRunRecordTests.c
index 8c551c1ab..6214f4aec 100644
--- a/src/std/rec/test/epicsRunRecordTests.c
+++ b/src/std/rec/test/epicsRunRecordTests.c
@@ -20,6 +20,7 @@ int asTest(void);
int linkRetargetLinkTest(void);
int linkInitTest(void);
int asyncSoftTest(void);
+int simmTest(void);
void epicsRunRecordTests(void)
{
@@ -41,5 +42,7 @@ void epicsRunRecordTests(void)
runTest(asyncSoftTest);
+ runTest(simmTest);
+
epicsExit(0); /* Trigger test harness */
}
diff --git a/src/std/rec/test/simmSetup.db b/src/std/rec/test/simmSetup.db
new file mode 100644
index 000000000..c8650e08b
--- /dev/null
+++ b/src/std/rec/test/simmSetup.db
@@ -0,0 +1,16 @@
+# no info
+record(ai, "ai-0") {
+}
+# only scan
+record(ai, "ai-1") {
+ field(SSCN,"2 second")
+}
+# only delay
+record(ai, "ai-2") {
+ field(SDLY,".234")
+}
+# scan and delay
+record(ai, "ai-3") {
+ field(SSCN,"5 second")
+ field(SDLY,".345")
+}
diff --git a/src/std/rec/test/simmTest.c b/src/std/rec/test/simmTest.c
new file mode 100644
index 000000000..a828ffe63
--- /dev/null
+++ b/src/std/rec/test/simmTest.c
@@ -0,0 +1,468 @@
+/*************************************************************************\
+* Copyright (c) 2017 ITER Organization
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+#include