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 @@ --> +

Simulation mode improvements

+ +

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).

+ +

Extend the dbServer API with init/run/pause/stop methods

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 +#include + +#include +#include +#include +#include +#include +#include + +#include "recSup.h" +#include "aiRecord.h" +#include "aoRecord.h" +#include "aaiRecord.h" +#include "aaoRecord.h" +#include "biRecord.h" +#include "boRecord.h" +#include "mbbiRecord.h" +#include "mbboRecord.h" +#include "mbbiDirectRecord.h" +#include "mbboDirectRecord.h" +#include "longinRecord.h" +#include "longoutRecord.h" +#include "int64inRecord.h" +#include "int64outRecord.h" +#include "stringinRecord.h" +#include "stringoutRecord.h" +#include "lsiRecord.h" +#include "lsoRecord.h" +#include "eventRecord.h" +#include "histogramRecord.h" +#include "waveformRecord.h" + +/* + * Tests for simulation mode + */ + +void simmTest_registerRecordDeviceDriver(struct dbBase *); + +static +void startSimmTestIoc(const char *dbfile) +{ + testdbPrepare(); + testdbReadDatabase("simmTest.dbd", NULL, NULL); + simmTest_registerRecordDeviceDriver(pdbbase); + testdbReadDatabase(dbfile, NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); +} + +static char *rawSupp[] = { + "ai", + "bi", + "mbbi", + "mbbiDirect", +}; + +static +int hasRawSimmSupport(const char *rectype) { + int i; + for (i = 0; i < (sizeof(rawSupp)/sizeof(rawSupp[0])); i++) + if (strcmp(rectype, rawSupp[i]) == 0) return 1; + return 0; +} + +#define PVNAMELENGTH 60 +static char nameVAL[PVNAMELENGTH]; +static char nameB0[PVNAMELENGTH]; +static char nameRVAL[PVNAMELENGTH]; +static char nameSGNL[PVNAMELENGTH]; +static char nameSIMM[PVNAMELENGTH]; +static char nameSIML[PVNAMELENGTH]; +static char nameSVAL[PVNAMELENGTH]; +static char nameSIOL[PVNAMELENGTH]; +static char nameSCAN[PVNAMELENGTH]; +static char namePROC[PVNAMELENGTH]; +static char namePACT[PVNAMELENGTH]; +static char nameSTAT[PVNAMELENGTH]; +static char nameSEVR[PVNAMELENGTH]; +static char nameSIMS[PVNAMELENGTH]; +static char nameTSE[PVNAMELENGTH]; +static char nameSimmode[PVNAMELENGTH]; +static char nameSimval[PVNAMELENGTH]; +static char nameSimvalNORD[PVNAMELENGTH]; +static char nameSimvalLEN[PVNAMELENGTH]; + +#define SETNAME(field) strcpy(name ## field, name); strcat(name ## field, "." #field) +static +void setNames(const char *name) +{ + SETNAME(VAL); SETNAME(B0); SETNAME(RVAL); SETNAME(SGNL); + SETNAME(SVAL); SETNAME(SIMM); SETNAME(SIML); SETNAME(SIOL); SETNAME(SIMS); + SETNAME(SCAN); SETNAME(PROC); SETNAME(PACT); + SETNAME(STAT); SETNAME(SEVR); SETNAME(TSE); + strcpy(nameSimmode, name); strcat(nameSimmode, ":simmode"); + strcpy(nameSimval, name); strcat(nameSimval, ":simval"); + strcpy(nameSimvalNORD, name); strcat(nameSimvalNORD, ":simval.NORD"); + strcpy(nameSimvalLEN, name); strcat(nameSimvalLEN, ":simval.LEN"); +} + +/* + * Parsing of info items and xsimm structure setting + */ +static +void testSimmSetup(void) +{ + aiRecord *precai; + + testDiag("##### Simm initialization #####"); + + /* no config */ + precai = (aiRecord*)testdbRecordPtr("ai-0"); + testOk(precai->simpvt == NULL, "ai-0.SIMPVT = %p == NULL [no callback]", precai->simpvt); + testOk(precai->sscn == USHRT_MAX, "ai-0.SSCN = %u == USHRT_MAX (not set)", precai->sscn); + testOk(precai->sdly < 0., "ai-0.SDLY = %g < 0.0 (not set)", precai->sdly); + + /* with SCAN */ + precai = (aiRecord*)testdbRecordPtr("ai-1"); + testOk(precai->sscn == 5, "ai-1.SSCN = %u == 5 (2 second)", precai->sscn); + testOk(precai->sdly < 0., "ai-1.SDLY = %g < 0.0 (not set)", precai->sdly); + + /* with DELAY */ + precai = (aiRecord*)testdbRecordPtr("ai-2"); + testOk(precai->sscn == USHRT_MAX, "ai-2.SSCN = %u == USHRT_MAX (not set)", precai->sscn); + testOk(precai->sdly == 0.234, "ai-2.SDLY = %g == 0.234", precai->sdly); + + /* with SCAN and DELAY */ + precai = (aiRecord*)testdbRecordPtr("ai-3"); + testOk(precai->sscn == 4, "ai-3.SSCN = %u == 4 (5 second)", precai->sscn); + testOk(precai->sdly == 0.345, "ai-3.SDLY = %g == 0.345", precai->sdly); +} + +/* + * SIMM triggered SCAN swapping, by writing to SIMM and through SIML + */ + +static +void testSimmToggle(const char *name, epicsEnum16 *psscn) +{ + testDiag("## SIMM toggle and SCAN swapping ##"); + + /* SIMM mode by setting the field */ + + testdbGetFieldEqual(nameSCAN, DBR_USHORT, 0); + testOk(*psscn == 1, "SSCN = %u == 1 (Event)", *psscn); + + testDiag("set SIMM to YES"); + testdbPutFieldOk(nameSIMM, DBR_STRING, "YES"); + testdbGetFieldEqual(nameSCAN, DBR_USHORT, 1); + testOk(*psscn == 0, "SSCN = %u == 0 (Passive)", *psscn); + + /* Change simm:SCAN when simmYES */ + testdbPutFieldOk(nameSCAN, DBR_USHORT, 3); + + testDiag("set SIMM to NO"); + testdbPutFieldOk(nameSIMM, DBR_STRING, "NO"); + testdbGetFieldEqual(nameSCAN, DBR_USHORT, 0); + testOk(*psscn == 3, "SSCN = %u == 3 (10 second)", *psscn); + *psscn = 1; + + if (hasRawSimmSupport(name)) { + testDiag("set SIMM to RAW"); + testdbPutFieldOk(nameSIMM, DBR_STRING, "RAW"); + testdbGetFieldEqual(nameSCAN, DBR_USHORT, 1); + testOk(*psscn == 0, "SSCN = %u == 0 (Passive)", *psscn); + + testDiag("set SIMM to NO"); + testdbPutFieldOk(nameSIMM, DBR_STRING, "NO"); + testdbGetFieldEqual(nameSCAN, DBR_USHORT, 0); + testOk(*psscn == 1, "SSCN = %u == 1 (Event)", *psscn); + } else { + testDiag("Record type %s has no support for simmRAW", name); + } + + /* SIMM mode through SIML */ + + testdbPutFieldOk(nameSIML, DBR_STRING, nameSimmode); + + testDiag("set SIMM (via SIML -> simmode) to YES"); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 1); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + + testdbGetFieldEqual(nameSIMM, DBR_USHORT, 1); + testdbGetFieldEqual(nameSCAN, DBR_USHORT, 1); + testOk(*psscn == 0, "SSCN = %u == 0 (Passive)", *psscn); + + testDiag("set SIMM (via SIML -> simmode) to NO"); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 0); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + + testdbGetFieldEqual(nameSIMM, DBR_USHORT, 0); + testdbGetFieldEqual(nameSCAN, DBR_USHORT, 0); + testOk(*psscn == 1, "SSCN = %u == 1 (Event)", *psscn); + + if (hasRawSimmSupport(name)) { + testDiag("set SIMM (via SIML -> simmode) to RAW"); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 2); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + + testdbGetFieldEqual(nameSIMM, DBR_USHORT, 2); + testdbGetFieldEqual(nameSCAN, DBR_USHORT, 1); + testOk(*psscn == 0, "SSCN = %u == 0 (Passive)", *psscn); + + testDiag("set SIMM (via SIML -> simmode) to NO"); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 0); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + + testdbGetFieldEqual(nameSIMM, DBR_USHORT, 0); + testdbGetFieldEqual(nameSCAN, DBR_USHORT, 0); + testOk(*psscn == 1, "SSCN = %u == 1 (Event)", *psscn); + } else { + testDiag("Record type %s has no support for simmRAW", name); + } +} + +/* + * Reading from SVAL (direct write or through SIOL link) + */ + +static +void testSvalRead(const char *name, + const epicsTimeStamp *mytime, + const epicsTimeStamp *svtime) +{ + epicsTimeStamp last; + + if (strcmp(name, "histogram") == 0) + strcpy(nameVAL, nameSGNL); + + if (strcmp(name, "aai") != 0 && + strcmp(name, "waveform") != 0 && + strcmp(name, "lsi") != 0) { + + testDiag("## Reading from SVAL ##"); + + testDiag("in simmNO, SVAL must be ignored"); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 0); + testdbPutFieldOk(nameVAL, DBR_LONG, 0); + if (strcmp(name, "stringin") == 0) + testdbPutFieldOk(nameSVAL, DBR_STRING, "1"); + else + testdbPutFieldOk(nameSVAL, DBR_USHORT, 1); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + testdbGetFieldEqual(nameVAL, DBR_USHORT, 0); + + testDiag("in simmYES, SVAL is used for VAL"); + testdbPutFieldOk(nameSIMS, DBR_USHORT, 0); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 1); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + testdbGetFieldEqual(nameVAL, DBR_USHORT, 1); + testDiag("No SIMS setting: STAT/SEVR == NO_ALARM"); + testdbGetFieldEqual(nameSTAT, DBR_STRING, "NO_ALARM"); + testdbGetFieldEqual(nameSEVR, DBR_USHORT, 0); + + if (hasRawSimmSupport(name)) { + testDiag("in simmRAW, SVAL is used for RVAL"); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 2); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + testdbGetFieldEqual(nameRVAL, DBR_USHORT, 1); + } else { + testDiag("Record type %s has no support for simmRAW", name); + } + } + + testDiag("## Reading from SIOL->SVAL ##"); + + /* Set SIOL link to simval */ + testdbPutFieldOk(nameSIOL, DBR_STRING, nameSimval); + + testDiag("in simmNO, SIOL->SVAL must be ignored"); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 0); + testdbPutFieldOk(nameVAL, DBR_LONG, 0); + testdbPutFieldOk(nameSimval, DBR_LONG, 1); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + testdbGetFieldEqual(nameVAL, DBR_USHORT, 0); + + testDiag("in simmYES, SIOL->SVAL is used for VAL"); + testdbPutFieldOk(nameSIMS, DBR_USHORT, 3); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 1); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + testdbGetFieldEqual(nameVAL, DBR_USHORT, 1); + testDiag("SIMS is INVALID: STAT/SEVR == SIMM/INVALID"); + testdbGetFieldEqual(nameSTAT, DBR_STRING, "SIMM"); + testdbGetFieldEqual(nameSEVR, DBR_USHORT, 3); + testdbPutFieldOk(nameSIMS, DBR_USHORT, 0); + + if (hasRawSimmSupport(name)) { + testDiag("in simmRAW, SIOL->SVAL is used for RVAL"); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 2); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + testdbGetFieldEqual(nameRVAL, DBR_USHORT, 1); + } else { + testDiag("Record type %s has no support for simmRAW", name); + } + + /* My timestamp must be later than simval's */ + testOk(epicsTimeLessThan(svtime, mytime), "simval time < my time [TSE = 0]"); + + testDiag("for TSE=-2 (from device) and simmYES, take time stamp from IOC or input link"); + + /* Set simmYES */ + testdbPutFieldOk(nameSimmode, DBR_USHORT, 1); + + /* Set TSE to -2 (from device) and reprocess: timestamps is taken through SIOL from simval */ + testdbPutFieldOk(nameTSE, DBR_SHORT, -2); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + testOk(epicsTimeEqual(svtime, mytime), "simval time == my time [TSE = -2]"); + last = *mytime; + + /* With TSE=-2 and no SIOL, timestamp is taken from IOC */ + testdbPutFieldOk(nameSIOL, DBR_STRING, ""); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + testOk(epicsTimeLessThan(&last, mytime), "new time stamp from IOC [TSE = -2, no SIOL]"); + + /* Reset TSE */ + testdbPutFieldOk(nameTSE, DBR_SHORT, 0); +} + +/* + * Writing through SIOL link + */ + +static +void testSiolWrite(const char *name, + const epicsTimeStamp *mytime) +{ + epicsTimeStamp now; + + testDiag("## Writing through SIOL ##"); + + /* Set SIOL link to simval */ + testdbPutFieldOk(nameSIOL, DBR_STRING, nameSimval); + + testDiag("in simmNO, SIOL must be ignored"); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 0); + if (strcmp(name, "mbboDirect") == 0) + testdbPutFieldOk(nameB0, DBR_LONG, 1); + else + testdbPutFieldOk(nameVAL, DBR_LONG, 1); + + if (strcmp(name, "aao") == 0) + testdbGetFieldEqual(nameSimvalNORD, DBR_USHORT, 0); + else if (strcmp(name, "lso") == 0) + testdbGetFieldEqual(nameSimvalLEN, DBR_USHORT, 0); + else + testdbGetFieldEqual(nameSimval, DBR_USHORT, 0); + + testDiag("in simmYES, SIOL is used to write VAL"); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 1); + if (strcmp(name, "mbboDirect") == 0) + testdbPutFieldOk(nameB0, DBR_LONG, 1); + else + testdbPutFieldOk(nameVAL, DBR_LONG, 1); + testdbGetFieldEqual(nameSimval, DBR_USHORT, 1); + + /* Set TSE to -2 (from device) and reprocess: timestamp is taken from IOC */ + epicsTimeGetCurrent(&now); + testdbPutFieldOk(nameTSE, DBR_SHORT, -2); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + testOk(epicsTimeLessThan(&now, mytime), "new time stamp from IOC [TSE = -2]"); + + /* Reset TSE */ + testdbPutFieldOk(nameTSE, DBR_SHORT, 0); +} + +/* + * Asynchronous processing using simm:DELAY + */ + +static +void testSimmDelay(const char *name, + epicsFloat64 *psdly, + const epicsTimeStamp *mytime) +{ + epicsTimeStamp now; + const double delay = 0.01; /* 10 ms */ + + testDiag("## Asynchronous processing with simm:DELAY ##"); + + /* Set delay to something just long enough */ + *psdly = delay; + + /* Process in simmNO: synchronous */ + testDiag("simm:DELAY and simmNO processes synchronously"); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 0); + epicsTimeGetCurrent(&now); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + testdbGetFieldEqual(namePACT, DBR_USHORT, 0); + testOk(epicsTimeLessThan(&now, mytime), "time stamp is recent"); + + /* Process in simmYES: asynchronous */ + testDiag("simm:DELAY and simmYES processes asynchronously"); + testdbPutFieldOk(nameSimmode, DBR_USHORT, 1); + testdbPutFieldOk(namePROC, DBR_LONG, 0); + testdbGetFieldEqual(namePACT, DBR_USHORT, 1); + epicsTimeGetCurrent(&now); + epicsThreadSleep(1.5*delay); + testdbGetFieldEqual(namePACT, DBR_USHORT, 0); + testOk(epicsTimeLessThan(&now, mytime), "time stamp taken from second pass processing"); + + /* Reset delay */ + *psdly = -1.; +} + +#define RUNALLTESTSREAD(type) \ + testDiag("################################################### Record Type " #type); \ + setNames(#type); \ + testSimmToggle(#type, &((type ## Record*)testdbRecordPtr(#type))->sscn); \ + testSvalRead(#type, &((type ## Record*)testdbRecordPtr(#type))->time, \ + &((type ## Record*)testdbRecordPtr(#type ":simval"))->time); \ + testSimmDelay(#type, &((type ## Record*)testdbRecordPtr(#type))->sdly, \ + &((type ## Record*)testdbRecordPtr(#type))->time) + +#define RUNALLTESTSWRITE(type) \ + testDiag("################################################### Record Type " #type); \ + setNames(#type); \ + testSimmToggle(#type, &((type ## Record*)testdbRecordPtr(#type))->sscn); \ + testSiolWrite(#type, &((type ## Record*)testdbRecordPtr(#type))->time); \ + testSimmDelay(#type, &((type ## Record*)testdbRecordPtr(#type))->sdly, \ + &((type ## Record*)testdbRecordPtr(#type))->time) + +static +void testAllRecTypes(void) +{ + RUNALLTESTSREAD(ai); + RUNALLTESTSWRITE(ao); + RUNALLTESTSREAD(aai); + RUNALLTESTSWRITE(aao); + RUNALLTESTSREAD(bi); + RUNALLTESTSWRITE(bo); + RUNALLTESTSREAD(mbbi); + RUNALLTESTSWRITE(mbbo); + RUNALLTESTSREAD(mbbiDirect); + RUNALLTESTSWRITE(mbboDirect); + RUNALLTESTSREAD(longin); + RUNALLTESTSWRITE(longout); + RUNALLTESTSREAD(int64in); + RUNALLTESTSWRITE(int64out); + RUNALLTESTSREAD(stringin); + RUNALLTESTSWRITE(stringout); + RUNALLTESTSREAD(lsi); + RUNALLTESTSWRITE(lso); + RUNALLTESTSREAD(event); + RUNALLTESTSREAD(waveform); + RUNALLTESTSREAD(histogram); +} + + +MAIN(simmTest) +{ + testPlan(0); + startSimmTestIoc("simmTest.db"); + + testSimmSetup(); + testAllRecTypes(); + + testIocShutdownOk(); + testdbCleanup(); + return testDone(); +} diff --git a/src/std/rec/test/simmTest.substitutions b/src/std/rec/test/simmTest.substitutions new file mode 100644 index 000000000..f3db61da0 --- /dev/null +++ b/src/std/rec/test/simmTest.substitutions @@ -0,0 +1,30 @@ +file "simmTestSimple.template" { +{ TYPE="ai" } +{ TYPE="ao" } +{ TYPE="bi" } +{ TYPE="bo" } +{ TYPE="mbbi" } +{ TYPE="mbbo" } +{ TYPE="mbbiDirect" } +{ TYPE="mbboDirect" } +{ TYPE="longin" } +{ TYPE="longout" } +{ TYPE="int64in" } +{ TYPE="int64out" } +{ TYPE="stringin" } +{ TYPE="stringout" } +{ TYPE="lsi" } +{ TYPE="lso" } +{ TYPE="event" } +} +file "simmTestArray.template" { +{ TYPE="aai" } +{ TYPE="aao" } +{ TYPE="waveform" } +} +file "simmTestHistogram.template" { +{ TYPE="histogram" } +} +file "simmSetup.db" { +{} +} diff --git a/src/std/rec/test/simmTestArray.template b/src/std/rec/test/simmTestArray.template new file mode 100644 index 000000000..36ca2c009 --- /dev/null +++ b/src/std/rec/test/simmTestArray.template @@ -0,0 +1,15 @@ +# Array type records +# Regular simulation mode and simm:SCAN tests +record($(TYPE), "$(TYPE)") { + field(SSCN,"Event") + field(FTVL,"SHORT") + field(NELM,"2") +} +record($(TYPE), "$(TYPE):simval") { + field(FTVL,"SHORT") + field(NELM,"2") +} +record(bo, "$(TYPE):simmode") { + field(ZNAM,"off") + field(ONAM,"on") +} diff --git a/src/std/rec/test/simmTestHistogram.template b/src/std/rec/test/simmTestHistogram.template new file mode 100644 index 000000000..574314f00 --- /dev/null +++ b/src/std/rec/test/simmTestHistogram.template @@ -0,0 +1,12 @@ +# Array type records +# Regular simulation mode and simm:SCAN tests +record($(TYPE), "$(TYPE)") { + field(SSCN,"Event") + field(NELM,"2") +} +record(ai, "$(TYPE):simval") { +} +record(bo, "$(TYPE):simmode") { + field(ZNAM,"off") + field(ONAM,"on") +} diff --git a/src/std/rec/test/simmTestSimple.template b/src/std/rec/test/simmTestSimple.template new file mode 100644 index 000000000..a1a73b5db --- /dev/null +++ b/src/std/rec/test/simmTestSimple.template @@ -0,0 +1,10 @@ +# Regular simulation mode and simm:SCAN tests +record($(TYPE), "$(TYPE)") { + field(SSCN,"Event") +} +record($(TYPE), "$(TYPE):simval") { +} +record(bo, "$(TYPE):simmode") { + field(ZNAM,"off") + field(ONAM,"on") +} diff --git a/src/std/rec/waveformRecord.c b/src/std/rec/waveformRecord.c index c06c48001..c987cfbc4 100644 --- a/src/std/rec/waveformRecord.c +++ b/src/std/rec/waveformRecord.c @@ -23,6 +23,7 @@ #include "epicsPrint.h" #include "epicsString.h" #include "alarm.h" +#include "callback.h" #include "dbAccess.h" #include "dbEvent.h" #include "dbFldTypes.h" @@ -31,6 +32,7 @@ #include "errMdef.h" #include "recSup.h" #include "recGbl.h" +#include "special.h" #include "cantProceed.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 static long cvt_dbaddr(DBADDR *); static long get_array_info(DBADDR *, long *, long *); @@ -95,7 +97,7 @@ static long init_record(struct dbCommon *pcommon, int pass) struct waveformRecord *prec = (struct waveformRecord *)pcommon; struct wfdset *pdset; - if (pass==0){ + if (pass == 0){ if (prec->nelm <= 0) prec->nelm = 1; if (prec->ftvl > DBF_ENUM) @@ -110,7 +112,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 dset defined */ if (!(pdset = (struct wfdset *)(prec->dset))) { @@ -144,9 +146,9 @@ static long process(struct dbCommon *pcommon) readValue(prec); /* read the new value */ if (!pact && prec->pact) return 0; - prec->pact = TRUE; prec->udf = FALSE; - recGblGetTimeStamp(prec); + prec->pact = TRUE; + recGblGetTimeStampSimm(prec, prec->simm, &prec->siol); monitor(prec); @@ -157,6 +159,26 @@ static long process(struct dbCommon *pcommon) return 0; } +static long special(DBADDR *paddr, int after) +{ + waveformRecord *prec = (waveformRecord *)(paddr->precord); + int special_type = paddr->special; + + switch(special_type) { + case(SPC_MOD): + if (dbGetFieldIndex(paddr) == waveformRecordSIMM) { + 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, "waveform: special"); + return(S_db_badChoice); + } +} + static long cvt_dbaddr(DBADDR *paddr) { waveformRecord *prec = (waveformRecord *) paddr->precord; @@ -304,43 +326,53 @@ static void monitor(waveformRecord *prec) static long readValue(waveformRecord *prec) { - long status; struct wfdset *pdset = (struct wfdset *) prec->dset; + long status = 0; - if (prec->pact == TRUE){ - return (*pdset->read_wf)(prec); + 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; - - if (prec->simm == menuYesNoNO){ + switch (prec->simm) { + case menuYesNoNO: { epicsUInt32 nord = prec->nord; - status = (*pdset->read_wf)(prec); + status = pdset->read_wf(prec); if (nord != prec->nord) db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG); - return status; + break; } - if (prec->simm == menuYesNoYES){ + case menuYesNoYES: { long nRequest = prec->nelm; - status = dbGetLink(&prec->siol, prec->ftvl, prec->bptr, 0, &nRequest); - /* nord set only for db links: needed for old db_access */ - if (!dbLinkIsConstant(&prec->siol)) { - prec->nord = nRequest; - db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG); - if (status == 0) - prec->udf=FALSE; + recGblSetSevr(prec, SIMM_ALARM, prec->sims); + if (prec->pact || (prec->sdly < 0.)) { + status = dbGetLink(&prec->siol, prec->ftvl, prec->bptr, 0, &nRequest); + if (status == 0) prec->udf = FALSE; + /* nord set only for db links: needed for old db_access */ + if (!dbLinkIsConstant(&prec->siol)) { + prec->nord = nRequest; + db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG); + } + 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; } - } else { - recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM); - return -1; + break; + } + + default: + recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM); + status = -1; } - recGblSetSevr(prec, SIMM_ALARM, prec->sims); return status; } - diff --git a/src/std/rec/waveformRecord.dbd.pod b/src/std/rec/waveformRecord.dbd.pod index db2fa05fb..82561d076 100644 --- a/src/std/rec/waveformRecord.dbd.pod +++ b/src/std/rec/waveformRecord.dbd.pod @@ -119,26 +119,53 @@ recordtype(waveform) { extra("void * bptr") } field(SIOL,DBF_INLINK) { - prompt("Sim Input Specifctn") + prompt("Simulation Input 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(MPST,DBF_MENU) { prompt("Post Value Monitors") promptgroup("80 - Display")