diff --git a/src/std/dev/Makefile b/src/std/dev/Makefile index 2a037ea42..f4f8f690f 100644 --- a/src/std/dev/Makefile +++ b/src/std/dev/Makefile @@ -30,6 +30,7 @@ dbRecStd_SRCS += devEventSoft.c dbRecStd_SRCS += devHistogramSoft.c dbRecStd_SRCS += devLiSoft.c dbRecStd_SRCS += devLoSoft.c +dbRecStd_SRCS += devLsiSoft.c dbRecStd_SRCS += devMbbiDirectSoft.c dbRecStd_SRCS += devMbbiDirectSoftRaw.c dbRecStd_SRCS += devMbbiSoft.c diff --git a/src/std/dev/devLsiSoft.c b/src/std/dev/devLsiSoft.c new file mode 100644 index 000000000..10dceb359 --- /dev/null +++ b/src/std/dev/devLsiSoft.c @@ -0,0 +1,60 @@ +/*************************************************************************\ +* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* Long String Input soft device support + * + * Author: Andrew Johnson + * Date: 2012-11-28 + */ + +#include +#include +#include + +#include "alarm.h" +#include "dbDefs.h" +#include "dbAccess.h" +#include "epicsTime.h" +#include "recGbl.h" +#include "devSup.h" +#include "link.h" +#include "lsiRecord.h" +#include "epicsExport.h" + +static long init_record(lsiRecord *prec) +{ + /* Handle CONSTANT links */ + if (prec->inp.type == CONSTANT) { + char tmp[MAX_STRING_SIZE]; + + if (recGblInitConstantLink(&prec->inp, DBF_STRING, tmp)) { + long len = prec->sizv; + + strncpy(prec->val, tmp, len); + prec->len = strlen(prec->val) + 1; + prec->udf = FALSE; + } + } + return 0; +} + +static long read_string(lsiRecord *prec) +{ + long status = dbGetLinkLS(&prec->inp, prec->val, prec->sizv, &prec->len); + + if (!status && + prec->tsel.type == CONSTANT && + prec->tse == epicsTimeEventDeviceTime) + dbGetTimeStamp(&prec->inp, &prec->time); + + return status; +} + +lsidset devLsiSoft = { + 5, NULL, NULL, init_record, NULL, read_string +}; +epicsExportAddress(dset, devLsiSoft); diff --git a/src/std/dev/devSoft.dbd b/src/std/dev/devSoft.dbd index da2f21ad4..babad358a 100644 --- a/src/std/dev/devSoft.dbd +++ b/src/std/dev/devSoft.dbd @@ -9,6 +9,7 @@ device(event,CONSTANT,devEventSoft,"Soft Channel") device(histogram,CONSTANT,devHistogramSoft,"Soft Channel") device(longin,CONSTANT,devLiSoft,"Soft Channel") device(longout,CONSTANT,devLoSoft,"Soft Channel") +device(lsi,CONSTANT,devLsiSoft,"Soft Channel") device(mbbi,CONSTANT,devMbbiSoft,"Soft Channel") device(mbbiDirect,CONSTANT,devMbbiDirectSoft,"Soft Channel") device(mbbo,CONSTANT,devMbboSoft,"Soft Channel") diff --git a/src/std/rec/Makefile b/src/std/rec/Makefile index a7098591c..d16b20b93 100644 --- a/src/std/rec/Makefile +++ b/src/std/rec/Makefile @@ -27,6 +27,7 @@ DBDINC += fanoutRecord DBDINC += histogramRecord DBDINC += longinRecord DBDINC += longoutRecord +DBDINC += lsiRecord DBDINC += mbbiRecord DBDINC += mbbiDirectRecord DBDINC += mbboRecord @@ -62,6 +63,7 @@ dbRecStd_SRCS += fanoutRecord.c dbRecStd_SRCS += histogramRecord.c dbRecStd_SRCS += longinRecord.c dbRecStd_SRCS += longoutRecord.c +dbRecStd_SRCS += lsiRecord.c dbRecStd_SRCS += mbbiRecord.c dbRecStd_SRCS += mbbiDirectRecord.c dbRecStd_SRCS += mbboRecord.c diff --git a/src/std/rec/lsiRecord.c b/src/std/rec/lsiRecord.c new file mode 100644 index 000000000..6e025fe51 --- /dev/null +++ b/src/std/rec/lsiRecord.c @@ -0,0 +1,277 @@ +/*************************************************************************\ +* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* Long String Input record type */ +/* + * Author: Andrew Johnson + * Date: 2012-11-27 + */ + +#include +#include +#include + +#include "dbDefs.h" +#include "errlog.h" +#include "alarm.h" +#include "cantProceed.h" +#include "dbAccess.h" +#include "dbEvent.h" +#include "dbFldTypes.h" +#include "errMdef.h" +#include "menuPost.h" +#include "menuYesNo.h" +#include "recSup.h" +#include "recGbl.h" +#include "special.h" +#define GEN_SIZE_OFFSET +#include "lsiRecord.h" +#undef GEN_SIZE_OFFSET +#include "epicsExport.h" + +static void monitor(lsiRecord *); +static long readValue(lsiRecord *); + + +static long init_record(lsiRecord *prec, int pass) +{ + lsidset *pdset; + + if (pass == 0) { + size_t sizv = prec->sizv; + + if (sizv < 16) { + sizv = 16; /* Enforce a minimum size for the VAL field */ + prec->sizv = sizv; + } + + prec->val = callocMustSucceed(1, sizv, "lsi::init_record"); + prec->len = 0; + prec->oval = callocMustSucceed(1, sizv, "lsi::init_record"); + prec->olen = 0; + return 0; + } + + if (prec->siml.type == CONSTANT) { + recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm); + } + + pdset = (lsidset *) prec->dset; + if (!pdset) { + recGblRecordError(S_dev_noDSET, prec, "lsi: init_record"); + return S_dev_noDSET; + } + + /* must have a read_string function */ + if ((pdset->number < 5) || (pdset->read_string == NULL) ) { + recGblRecordError(S_dev_missingSup, prec, "lsi: init_record"); + return S_dev_missingSup; + } + + if (pdset->init_record) { + long status = pdset->init_record(prec); + + if (status) + return(status); + } + + return 0; +} + +static long process(lsiRecord *prec) +{ + int pact = prec->pact; + lsidset *pdset = (lsidset *) prec->dset; + long status = 0; + + if ((pdset == NULL) || (pdset->read_string == NULL)) { + prec->pact = TRUE; + recGblRecordError(S_dev_missingSup, prec, "lsi: read_string"); + return S_dev_missingSup; + } + + status = readValue(prec); /* read the new value */ + if (!pact && prec->pact) + return 0; + + prec->pact = TRUE; + recGblGetTimeStamp(prec); + + monitor(prec); + + /* Wrap up */ + recGblFwdLink(prec); + prec->pact = FALSE; + return status; +} + +static long cvt_dbaddr(DBADDR *paddr) +{ + lsiRecord *prec = (lsiRecord *) paddr->precord; + int fieldIndex = dbGetFieldIndex(paddr); + + if (fieldIndex == lsiRecordVAL) { + paddr->pfield = prec->val; + paddr->special = SPC_MOD; + } + else if (fieldIndex == lsiRecordOVAL) { + paddr->pfield = prec->oval; + paddr->special = SPC_NOMOD; + } + else { + errlogPrintf("lsiRecord::cvt_dbaddr called for %s.%s\n", + prec->name, paddr->pfldDes->name); + return -1; + } + + paddr->no_elements = 1; + paddr->field_type = DBF_STRING; + paddr->dbr_field_type = DBF_STRING; + paddr->field_size = prec->sizv; + return 0; +} + +static long get_array_info(DBADDR *paddr, long *no_elements, long *offset) +{ + lsiRecord *prec = (lsiRecord *) paddr->precord; + int fieldIndex = dbGetFieldIndex(paddr); + + if (fieldIndex == lsiRecordVAL) + *no_elements = prec->len; + else if (fieldIndex == lsiRecordOVAL) + *no_elements = prec->olen; + else + return -1; + + *offset = 0; + return 0; +} + +static long put_array_info(DBADDR *paddr, long nNew) +{ + lsiRecord *prec = (lsiRecord *) paddr->precord; + + if (nNew == prec->sizv) + --nNew; /* truncated string */ + prec->val[nNew] = 0; + + return 0; +} + +static long special(DBADDR *paddr, int after) +{ + lsiRecord *prec = (lsiRecord *) paddr->precord; + + if (!after) + return 0; + + prec->len = strlen(prec->val) + 1; + db_post_events(prec, &prec->len, DBE_VALUE | DBE_LOG); + + return 0; +} + +static void monitor(lsiRecord *prec) +{ + epicsUInt16 events = recGblResetAlarms(prec); + + if (prec->len != prec->olen || + memcmp(prec->oval, prec->val, prec->len)) { + events |= DBE_VALUE | DBE_LOG; + memcpy(prec->oval, prec->val, prec->len); + } + + if (prec->len != prec->olen) { + prec->olen = prec->len; + db_post_events(prec, &prec->len, DBE_VALUE | DBE_LOG); + } + + if (prec->mpst == menuPost_Always) + events |= DBE_VALUE; + if (prec->apst == menuPost_Always) + events |= DBE_LOG; + + if (events) + db_post_events(prec, prec->val, events); +} + +static long readValue(lsiRecord *prec) +{ + long status; + lsidset *pdset = (lsidset *) prec->dset; + + if (prec->pact) + goto read; + + status = dbGetLink(&prec->siml, DBR_USHORT, &prec->simm, 0, 0); + if (status) + return status; + + switch (prec->simm) { + case menuYesNoYES: + recGblSetSevr(prec, SIMM_ALARM, prec->sims); + status = dbGetLinkLS(&prec->siol, prec->val, prec->sizv, &prec->len); + break; + + case menuYesNoNO: +read: + status = pdset->read_string(prec); + break; + + default: + recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM); + status = -1; + } + + if (!status) + prec->udf = FALSE; + + return status; +} + + +/* Create Record Support Entry Table*/ + +#define report NULL +#define initialize NULL +/* init_record */ +/* process */ +/* special */ +#define get_value NULL +/* cvt_dbaddr */ +/* get_array_info */ +/* put_array_info */ +#define get_units NULL +#define get_precision NULL +#define get_enum_str NULL +#define get_enum_strs NULL +#define put_enum_str NULL +#define get_graphic_double NULL +#define get_control_double NULL +#define get_alarm_double NULL + +rset lsiRSET = { + RSETNUMBER, + report, + initialize, + init_record, + process, + special, + get_value, + cvt_dbaddr, + get_array_info, + put_array_info, + get_units, + get_precision, + get_enum_str, + get_enum_strs, + put_enum_str, + get_graphic_double, + get_control_double, + get_alarm_double +}; +epicsExportAddress(rset, lsiRSET); diff --git a/src/std/rec/lsiRecord.dbd b/src/std/rec/lsiRecord.dbd new file mode 100644 index 000000000..be14cf552 --- /dev/null +++ b/src/std/rec/lsiRecord.dbd @@ -0,0 +1,88 @@ +#************************************************************************* +# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne +# National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +recordtype(lsi) { + include "dbCommon.dbd" + %#include "devSup.h" + % + %/* Declare Device Support Entry Table */ + %typedef struct lsidset { + % long number; + % DEVSUPFUN report; + % DEVSUPFUN init; + % DEVSUPFUN init_record; + % DEVSUPFUN get_ioint_info; + % DEVSUPFUN read_string; + %} lsidset; + % + field(VAL,DBF_NOACCESS) { + prompt("Current Value") + asl(ASL0) + pp(TRUE) + special(SPC_DBADDR) + extra("char *val") + } + field(OVAL,DBF_NOACCESS) { + prompt("Old Value") + special(SPC_DBADDR) + interest(3) + extra("char *oval") + } + field(SIZV,DBF_USHORT) { + prompt("Size of buffers") + promptgroup(GUI_OUTPUT) + special(SPC_NOMOD) + interest(1) + initial("41") + } + field(LEN,DBF_ULONG) { + prompt("Length of VAL") + special(SPC_NOMOD) + } + field(OLEN,DBF_ULONG) { + prompt("Length of OVAL") + special(SPC_NOMOD) + } + field(INP,DBF_INLINK) { + prompt("Input Specification") + promptgroup(GUI_INPUTS) + interest(1) + } + field(MPST,DBF_MENU) { + prompt("Post Value Monitors") + promptgroup(GUI_DISPLAY) + interest(1) + menu(menuPost) + } + field(APST,DBF_MENU) { + prompt("Post Archive Monitors") + promptgroup(GUI_DISPLAY) + interest(1) + menu(menuPost) + } + field(SIML,DBF_INLINK) { + prompt("Simulation Mode Link") + promptgroup(GUI_INPUTS) + interest(2) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + interest(2) + menu(menuYesNo) + } + field(SIMS,DBF_MENU) { + prompt("Simulation Mode Severity") + promptgroup(GUI_INPUTS) + interest(2) + menu(menuAlarmSevr) + } + field(SIOL,DBF_INLINK) { + prompt("Sim Input Specifctn") + promptgroup(GUI_INPUTS) + interest(2) + } +}