Merged printf-record branch
Adds three new record types: printf, lsi and lso. Provides device support for all three.
This commit is contained in:
@@ -47,6 +47,7 @@ menuGlobal_DBD += menuFtype.dbd
|
||||
menuGlobal_DBD += menuIvoa.dbd
|
||||
menuGlobal_DBD += menuOmsl.dbd
|
||||
menuGlobal_DBD += menuPini.dbd
|
||||
menuGlobal_DBD += menuPost.dbd
|
||||
menuGlobal_DBD += menuPriority.dbd
|
||||
menuGlobal_DBD += menuScan.dbd
|
||||
menuGlobal_DBD += menuYesNo.dbd
|
||||
|
||||
@@ -583,10 +583,8 @@ long dbNameToAddr(const char *pname, DBADDR *paddr)
|
||||
{
|
||||
DBENTRY dbEntry;
|
||||
dbFldDes *pflddes;
|
||||
struct rset *prset;
|
||||
long status = 0;
|
||||
long no_elements = 1;
|
||||
short dbfType, dbrType, field_size;
|
||||
short dbfType;
|
||||
|
||||
if (!pname || !*pname || !pdbbase)
|
||||
return S_db_notFound;
|
||||
@@ -601,48 +599,49 @@ long dbNameToAddr(const char *pname, DBADDR *paddr)
|
||||
status = dbGetAttributePart(&dbEntry, &pname);
|
||||
if (status) goto finish;
|
||||
|
||||
pflddes = dbEntry.pflddes;
|
||||
dbfType = pflddes->field_type;
|
||||
|
||||
paddr->precord = dbEntry.precnode->precord;
|
||||
paddr->pfield = dbEntry.pfield;
|
||||
pflddes = dbEntry.pflddes;
|
||||
paddr->pfldDes = pflddes;
|
||||
paddr->no_elements = 1;
|
||||
paddr->field_type = dbfType;
|
||||
paddr->field_size = pflddes->size;
|
||||
paddr->special = pflddes->special;
|
||||
paddr->dbr_field_type = mapDBFToDBR[dbfType];
|
||||
|
||||
dbfType = pflddes->field_type;
|
||||
dbrType = mapDBFToDBR[dbfType];
|
||||
field_size = pflddes->size;
|
||||
if (paddr->special == SPC_DBADDR) {
|
||||
struct rset *prset = dbGetRset(paddr);
|
||||
|
||||
/* Let record type modify paddr */
|
||||
if (prset && prset->cvt_dbaddr) {
|
||||
status = prset->cvt_dbaddr(paddr);
|
||||
if (status)
|
||||
goto finish;
|
||||
dbfType = paddr->field_type;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle field modifiers */
|
||||
if (*pname++ == '$') {
|
||||
/* Some field types can be accessed as char arrays */
|
||||
if (dbfType == DBF_STRING) {
|
||||
dbfType = DBF_CHAR;
|
||||
dbrType = DBR_CHAR;
|
||||
no_elements = field_size;
|
||||
field_size = 1;
|
||||
paddr->no_elements = paddr->field_size;
|
||||
paddr->field_type = DBF_CHAR;
|
||||
paddr->field_size = 1;
|
||||
paddr->dbr_field_type = DBR_CHAR;
|
||||
} else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
|
||||
/* Clients see a char array, but keep original dbfType */
|
||||
dbrType = DBR_CHAR;
|
||||
no_elements = PVNAME_STRINGSZ + 12;
|
||||
field_size = 1;
|
||||
paddr->no_elements = PVNAME_STRINGSZ + 12;
|
||||
paddr->field_size = 1;
|
||||
paddr->dbr_field_type = DBR_CHAR;
|
||||
} else {
|
||||
status = S_dbLib_fieldNotFound;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
paddr->pfldDes = pflddes;
|
||||
paddr->field_type = dbfType;
|
||||
paddr->dbr_field_type = dbrType;
|
||||
paddr->field_size = field_size;
|
||||
paddr->special = pflddes->special;
|
||||
paddr->no_elements = no_elements;
|
||||
|
||||
if ((paddr->special == SPC_DBADDR) &&
|
||||
(prset = dbGetRset(paddr)) &&
|
||||
prset->cvt_dbaddr)
|
||||
/* cvt_dbaddr routine may change any of these elements of paddr:
|
||||
* pfield, no_elements, element_offset, field_type,
|
||||
* dbr_field_type, field_size, and/or special.
|
||||
*/
|
||||
status = prset->cvt_dbaddr(paddr);
|
||||
|
||||
finish:
|
||||
dbFinishEntry(&dbEntry);
|
||||
return status;
|
||||
@@ -825,7 +824,7 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
|
||||
/* check for array */
|
||||
if ((!pfl || pfl->type == dbfl_type_rec) &&
|
||||
paddr->special == SPC_DBADDR &&
|
||||
paddr->pfldDes->special == SPC_DBADDR &&
|
||||
no_elements > 1 &&
|
||||
(prset = dbGetRset(paddr)) &&
|
||||
prset->get_array_info) {
|
||||
@@ -1182,7 +1181,7 @@ long dbPut(DBADDR *paddr, short dbrType,
|
||||
struct rset *prset = dbGetRset(paddr);
|
||||
long offset = 0;
|
||||
|
||||
if (paddr->special == SPC_DBADDR &&
|
||||
if (paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->get_array_info) {
|
||||
long dummy;
|
||||
|
||||
@@ -1195,7 +1194,7 @@ long dbPut(DBADDR *paddr, short dbrType,
|
||||
|
||||
/* update array info */
|
||||
if (!status &&
|
||||
paddr->special == SPC_DBADDR &&
|
||||
paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->put_array_info) {
|
||||
status = prset->put_array_info(paddr, nRequest);
|
||||
}
|
||||
|
||||
@@ -649,3 +649,62 @@ void dbScanFwdLink(struct link *plink)
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper functions for long string support */
|
||||
|
||||
long dbLoadLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
|
||||
epicsUInt32 *plen)
|
||||
{
|
||||
if (plink->type == CONSTANT &&
|
||||
plink->value.constantStr) {
|
||||
strncpy(pbuffer, plink->value.constantStr, --size);
|
||||
pbuffer[size] = 0;
|
||||
*plen = strlen(pbuffer) + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return S_db_notFound;
|
||||
}
|
||||
|
||||
long dbGetLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
|
||||
epicsUInt32 *plen)
|
||||
{
|
||||
int dtyp = dbGetLinkDBFtype(plink);
|
||||
long len = size;
|
||||
long status;
|
||||
|
||||
if (dtyp < 0) /* Not connected */
|
||||
return 0;
|
||||
|
||||
if (dtyp == DBR_CHAR || dtyp == DBF_UCHAR) {
|
||||
status = dbGetLink(plink, dtyp, pbuffer, 0, &len);
|
||||
}
|
||||
else if (size >= MAX_STRING_SIZE)
|
||||
status = dbGetLink(plink, DBR_STRING, pbuffer, 0, 0);
|
||||
else {
|
||||
/* pbuffer is too small to fetch using DBR_STRING */
|
||||
char tmp[MAX_STRING_SIZE];
|
||||
|
||||
status = dbGetLink(plink, DBR_STRING, tmp, 0, 0);
|
||||
if (!status)
|
||||
strncpy(pbuffer, tmp, len - 1);
|
||||
}
|
||||
if (!status) {
|
||||
pbuffer[--len] = 0;
|
||||
*plen = strlen(pbuffer) + 1;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
long dbPutLinkLS(struct link *plink, char *pbuffer, epicsUInt32 len)
|
||||
{
|
||||
int dtyp = dbGetLinkDBFtype(plink);
|
||||
|
||||
if (dtyp < 0)
|
||||
return 0; /* Not connected */
|
||||
|
||||
if (dtyp == DBR_CHAR || dtyp == DBF_UCHAR)
|
||||
return dbPutLink(plink, dtyp, pbuffer, len);
|
||||
|
||||
return dbPutLink(plink, DBR_STRING, pbuffer, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,13 @@ epicsShareFunc long dbPutLink(struct link *, short dbrType,
|
||||
const void *pbuffer, long nRequest);
|
||||
epicsShareFunc void dbScanFwdLink(struct link *plink);
|
||||
|
||||
epicsShareFunc long dbLoadLinkLS(struct link *plink, char *pbuffer,
|
||||
epicsUInt32 size, epicsUInt32 *plen);
|
||||
epicsShareFunc long dbGetLinkLS(struct link *plink, char *pbuffer,
|
||||
epicsUInt32 buffer_size, epicsUInt32 *plen);
|
||||
epicsShareFunc long dbPutLinkLS(struct link *plink, char *pbuffer,
|
||||
epicsUInt32 len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
11
src/ioc/db/menuPost.dbd
Normal file
11
src/ioc/db/menuPost.dbd
Normal file
@@ -0,0 +1,11 @@
|
||||
#*************************************************************************
|
||||
# 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.
|
||||
#*************************************************************************
|
||||
|
||||
menu(menuPost) {
|
||||
choice(menuPost_OnChange, "On Change")
|
||||
choice(menuPost_Always, "Always")
|
||||
}
|
||||
@@ -30,6 +30,8 @@ dbRecStd_SRCS += devEventSoft.c
|
||||
dbRecStd_SRCS += devHistogramSoft.c
|
||||
dbRecStd_SRCS += devLiSoft.c
|
||||
dbRecStd_SRCS += devLoSoft.c
|
||||
dbRecStd_SRCS += devLsiSoft.c
|
||||
dbRecStd_SRCS += devLsoSoft.c
|
||||
dbRecStd_SRCS += devMbbiDirectSoft.c
|
||||
dbRecStd_SRCS += devMbbiDirectSoftRaw.c
|
||||
dbRecStd_SRCS += devMbbiSoft.c
|
||||
@@ -38,6 +40,7 @@ dbRecStd_SRCS += devMbboDirectSoft.c
|
||||
dbRecStd_SRCS += devMbboDirectSoftRaw.c
|
||||
dbRecStd_SRCS += devMbboSoft.c
|
||||
dbRecStd_SRCS += devMbboSoftRaw.c
|
||||
dbRecStd_SRCS += devPrintfSoft.c
|
||||
dbRecStd_SRCS += devSASoft.c
|
||||
dbRecStd_SRCS += devSiSoft.c
|
||||
dbRecStd_SRCS += devSoSoft.c
|
||||
@@ -55,12 +58,14 @@ dbRecStd_SRCS += devAoSoftCallback.c
|
||||
dbRecStd_SRCS += devBoSoftCallback.c
|
||||
dbRecStd_SRCS += devCalcoutSoftCallback.c
|
||||
dbRecStd_SRCS += devLoSoftCallback.c
|
||||
dbRecStd_SRCS += devLsoSoftCallback.c
|
||||
dbRecStd_SRCS += devMbboSoftCallback.c
|
||||
dbRecStd_SRCS += devMbboDirectSoftCallback.c
|
||||
dbRecStd_SRCS += devPrintfSoftCallback.c
|
||||
dbRecStd_SRCS += devSoSoftCallback.c
|
||||
|
||||
dbRecStd_SRCS += devTimestamp.c
|
||||
dbRecStd_SRCS += devSoStdio.c
|
||||
dbRecStd_SRCS += devStdio.c
|
||||
|
||||
dbRecStd_SRCS += asSubRecordFunctions.c
|
||||
|
||||
|
||||
42
src/std/dev/devLsiSoft.c
Normal file
42
src/std/dev/devLsiSoft.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*************************************************************************\
|
||||
* 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 "dbAccess.h"
|
||||
#include "epicsTime.h"
|
||||
#include "link.h"
|
||||
#include "lsiRecord.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
static long init_record(lsiRecord *prec)
|
||||
{
|
||||
dbLoadLinkLS(&prec->inp, prec->val, prec->sizv, &prec->len);
|
||||
|
||||
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);
|
||||
26
src/std/dev/devLsoSoft.c
Normal file
26
src/std/dev/devLsoSoft.c
Normal file
@@ -0,0 +1,26 @@
|
||||
/*************************************************************************\
|
||||
* 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 Output soft device support
|
||||
*
|
||||
* Author: Andrew Johnson
|
||||
* Date: 2012-11-29
|
||||
*/
|
||||
|
||||
#include "dbAccess.h"
|
||||
#include "lsoRecord.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
static long write_string(lsoRecord *prec)
|
||||
{
|
||||
return dbPutLinkLS(&prec->out, prec->val, prec->len);
|
||||
}
|
||||
|
||||
lsodset devLsoSoft = {
|
||||
5, NULL, NULL, NULL, NULL, write_string
|
||||
};
|
||||
epicsExportAddress(dset, devLsoSoft);
|
||||
51
src/std/dev/devLsoSoftCallback.c
Normal file
51
src/std/dev/devLsoSoftCallback.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/* $Revision-Id$ */
|
||||
/*
|
||||
* Author: Andrew Johnson
|
||||
* Date: 30 Nov 2012
|
||||
*/
|
||||
|
||||
#include "alarm.h"
|
||||
#include "dbAccess.h"
|
||||
#include "recGbl.h"
|
||||
#include "lsoRecord.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
static long write_string(lsoRecord *prec)
|
||||
{
|
||||
struct link *plink = &prec->out;
|
||||
int dtyp = dbGetLinkDBFtype(plink);
|
||||
long len = prec->len;
|
||||
long status;
|
||||
|
||||
if (prec->pact || dtyp < 0)
|
||||
return 0;
|
||||
|
||||
if (dtyp != DBR_CHAR && dtyp != DBF_UCHAR) {
|
||||
dtyp = DBR_STRING;
|
||||
len = 1;
|
||||
}
|
||||
|
||||
if (plink->type != CA_LINK)
|
||||
return dbPutLink(plink, dtyp, prec->val, len);
|
||||
|
||||
status = dbCaPutLinkCallback(plink, dtyp, prec->val, len,
|
||||
dbCaCallbackProcess, plink);
|
||||
if (status) {
|
||||
recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
|
||||
return status;
|
||||
}
|
||||
|
||||
prec->pact = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lsodset devLsoSoftCallback = {
|
||||
5, NULL, NULL, NULL, NULL, write_string
|
||||
};
|
||||
epicsExportAddress(dset, devLsoSoftCallback);
|
||||
26
src/std/dev/devPrintfSoft.c
Normal file
26
src/std/dev/devPrintfSoft.c
Normal file
@@ -0,0 +1,26 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/* $Revision-Id$ */
|
||||
/*
|
||||
* Author: Andrew Johnson
|
||||
* Date: 28 Sept 2012
|
||||
*/
|
||||
|
||||
#include "dbAccess.h"
|
||||
#include "printfRecord.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
static long write_string(printfRecord *prec)
|
||||
{
|
||||
return dbPutLinkLS(&prec->out, prec->val, prec->len);
|
||||
}
|
||||
|
||||
printfdset devPrintfSoft = {
|
||||
5, NULL, NULL, NULL, NULL, write_string
|
||||
};
|
||||
epicsExportAddress(dset, devPrintfSoft);
|
||||
|
||||
51
src/std/dev/devPrintfSoftCallback.c
Normal file
51
src/std/dev/devPrintfSoftCallback.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/* $Revision-Id$ */
|
||||
/*
|
||||
* Author: Andrew Johnson
|
||||
* Date: 28 Sept 2012
|
||||
*/
|
||||
|
||||
#include "alarm.h"
|
||||
#include "dbAccess.h"
|
||||
#include "recGbl.h"
|
||||
#include "printfRecord.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
static long write_string(printfRecord *prec)
|
||||
{
|
||||
struct link *plink = &prec->out;
|
||||
int dtyp = dbGetLinkDBFtype(plink);
|
||||
long len = prec->len;
|
||||
long status;
|
||||
|
||||
if (prec->pact || dtyp < 0)
|
||||
return 0;
|
||||
|
||||
if (dtyp != DBR_CHAR && dtyp != DBF_UCHAR) {
|
||||
dtyp = DBR_STRING;
|
||||
len = 1;
|
||||
}
|
||||
|
||||
if (plink->type != CA_LINK)
|
||||
return dbPutLink(plink, dtyp, prec->val, len);
|
||||
|
||||
status = dbCaPutLinkCallback(plink, dtyp, prec->val, len,
|
||||
dbCaCallbackProcess, plink);
|
||||
if (status) {
|
||||
recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
|
||||
return status;
|
||||
}
|
||||
|
||||
prec->pact = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
printfdset devPrintfSoftCallback = {
|
||||
5, NULL, NULL, NULL, NULL, write_string
|
||||
};
|
||||
epicsExportAddress(dset, devPrintfSoftCallback);
|
||||
@@ -1,108 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2008 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/* $Revision-Id$ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "devSup.h"
|
||||
#include "errlog.h"
|
||||
#include "recGbl.h"
|
||||
#include "recSup.h"
|
||||
#include "stringoutRecord.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
typedef int (*PRINTFFUNC)(const char *fmt, ...);
|
||||
|
||||
static int stderrPrintf(const char *fmt, ...);
|
||||
static int logPrintf(const char *fmt, ...);
|
||||
|
||||
|
||||
static struct outStream {
|
||||
const char *name;
|
||||
PRINTFFUNC print;
|
||||
} outStreams[] = {
|
||||
{"stdout", printf},
|
||||
{"stderr", stderrPrintf},
|
||||
{"errlog", logPrintf},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static int stderrPrintf(const char *fmt, ...) {
|
||||
va_list pvar;
|
||||
int retval;
|
||||
|
||||
va_start(pvar, fmt);
|
||||
retval = vfprintf(stderr, fmt, pvar);
|
||||
va_end (pvar);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int logPrintf(const char *fmt, ...) {
|
||||
va_list pvar;
|
||||
int retval;
|
||||
|
||||
va_start(pvar, fmt);
|
||||
retval = errlogVprintf(fmt, pvar);
|
||||
va_end (pvar);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static long add(dbCommon *pcommon) {
|
||||
stringoutRecord *prec = (stringoutRecord *) pcommon;
|
||||
struct outStream *pstream;
|
||||
|
||||
if (prec->out.type != INST_IO)
|
||||
return S_dev_badOutType;
|
||||
|
||||
for (pstream = outStreams; pstream->name; ++pstream) {
|
||||
if (strcmp(prec->out.value.instio.string, pstream->name) == 0) {
|
||||
prec->dpvt = pstream;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
prec->dpvt = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static long del(dbCommon *pcommon) {
|
||||
stringoutRecord *prec = (stringoutRecord *) pcommon;
|
||||
|
||||
prec->dpvt = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dsxt dsxtSoStdio = {
|
||||
add, del
|
||||
};
|
||||
|
||||
static long init(int pass)
|
||||
{
|
||||
if (pass == 0) devExtend(&dsxtSoStdio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long write_string(stringoutRecord *prec)
|
||||
{
|
||||
struct outStream *pstream = (struct outStream *)prec->dpvt;
|
||||
if (pstream)
|
||||
pstream->print("%s\n", prec->val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create the dset for devSoStdio */
|
||||
static struct {
|
||||
dset common;
|
||||
DEVSUPFUN write;
|
||||
} devSoStdio = {
|
||||
{5, NULL, init, NULL, NULL}, write_string
|
||||
};
|
||||
epicsExportAddress(dset, devSoStdio);
|
||||
@@ -9,10 +9,13 @@ 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(lso,CONSTANT,devLsoSoft,"Soft Channel")
|
||||
device(mbbi,CONSTANT,devMbbiSoft,"Soft Channel")
|
||||
device(mbbiDirect,CONSTANT,devMbbiDirectSoft,"Soft Channel")
|
||||
device(mbbo,CONSTANT,devMbboSoft,"Soft Channel")
|
||||
device(mbboDirect,CONSTANT,devMbboDirectSoft,"Soft Channel")
|
||||
device(printf,CONSTANT,devPrintfSoft,"Soft Channel")
|
||||
device(stringin,CONSTANT,devSiSoft,"Soft Channel")
|
||||
device(stringout,CONSTANT,devSoSoft,"Soft Channel")
|
||||
device(subArray,CONSTANT,devSASoft,"Soft Channel")
|
||||
@@ -34,10 +37,12 @@ device(bo,CONSTANT,devBoSoftCallback,"Async Soft Channel")
|
||||
device(calcout,CONSTANT,devCalcoutSoftCallback,"Async Soft Channel")
|
||||
device(longin,CONSTANT,devLiSoftCallback,"Async Soft Channel")
|
||||
device(longout,CONSTANT,devLoSoftCallback,"Async Soft Channel")
|
||||
device(lso,CONSTANT,devLsoSoftCallback,"Async Soft Channel")
|
||||
device(mbbi,CONSTANT,devMbbiSoftCallback,"Async Soft Channel")
|
||||
device(mbbiDirect,CONSTANT,devMbbiDirectSoftCallback,"Async Soft Channel")
|
||||
device(mbbo,CONSTANT,devMbboSoftCallback,"Async Soft Channel")
|
||||
device(mbboDirect,CONSTANT,devMbboDirectSoftCallback,"Async Soft Channel")
|
||||
device(printf,CONSTANT,devPrintfSoftCallback,"Async Soft Channel")
|
||||
device(stringin,CONSTANT,devSiSoftCallback,"Async Soft Channel")
|
||||
device(stringout,CONSTANT,devSoSoftCallback,"Async Soft Channel")
|
||||
|
||||
@@ -49,6 +54,8 @@ device(bo, INST_IO,devBoGeneralTime,"General Time")
|
||||
device(longin, INST_IO,devLiGeneralTime,"General Time")
|
||||
device(stringin,INST_IO,devSiGeneralTime,"General Time")
|
||||
|
||||
device(lso,INST_IO,devLsoStdio,"stdio")
|
||||
device(printf,INST_IO,devPrintfStdio,"stdio")
|
||||
device(stringout,INST_IO,devSoStdio,"stdio")
|
||||
|
||||
device(bi, INST_IO, devBiDbState, "Db State")
|
||||
|
||||
212
src/std/dev/devStdio.c
Normal file
212
src/std/dev/devStdio.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2008 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/* $Revision-Id$ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "devSup.h"
|
||||
#include "errlog.h"
|
||||
#include "recGbl.h"
|
||||
#include "recSup.h"
|
||||
#include "lsoRecord.h"
|
||||
#include "printfRecord.h"
|
||||
#include "stringoutRecord.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
typedef int (*PRINTFFUNC)(const char *fmt, ...);
|
||||
|
||||
static int stderrPrintf(const char *fmt, ...);
|
||||
static int logPrintf(const char *fmt, ...);
|
||||
|
||||
|
||||
static struct outStream {
|
||||
const char *name;
|
||||
PRINTFFUNC print;
|
||||
} outStreams[] = {
|
||||
{"stdout", printf},
|
||||
{"stderr", stderrPrintf},
|
||||
{"errlog", logPrintf},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static int stderrPrintf(const char *fmt, ...) {
|
||||
va_list pvar;
|
||||
int retval;
|
||||
|
||||
va_start(pvar, fmt);
|
||||
retval = vfprintf(stderr, fmt, pvar);
|
||||
va_end (pvar);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int logPrintf(const char *fmt, ...) {
|
||||
va_list pvar;
|
||||
int retval;
|
||||
|
||||
va_start(pvar, fmt);
|
||||
retval = errlogVprintf(fmt, pvar);
|
||||
va_end (pvar);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* lso device support */
|
||||
|
||||
static long add_lso(dbCommon *pcommon) {
|
||||
lsoRecord *prec = (lsoRecord *) pcommon;
|
||||
struct outStream *pstream;
|
||||
|
||||
if (prec->out.type != INST_IO)
|
||||
return S_dev_badOutType;
|
||||
|
||||
for (pstream = outStreams; pstream->name; ++pstream) {
|
||||
if (strcmp(prec->out.value.instio.string, pstream->name) == 0) {
|
||||
prec->dpvt = pstream;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
prec->dpvt = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static long del_lso(dbCommon *pcommon) {
|
||||
lsoRecord *prec = (lsoRecord *) pcommon;
|
||||
|
||||
prec->dpvt = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dsxt dsxtLsoStdio = {
|
||||
add_lso, del_lso
|
||||
};
|
||||
|
||||
static long init_lso(int pass)
|
||||
{
|
||||
if (pass == 0) devExtend(&dsxtLsoStdio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long write_lso(lsoRecord *prec)
|
||||
{
|
||||
struct outStream *pstream = (struct outStream *)prec->dpvt;
|
||||
if (pstream)
|
||||
pstream->print("%s\n", prec->val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lsodset devLsoStdio = {
|
||||
5, NULL, init_lso, NULL, NULL, write_lso
|
||||
};
|
||||
epicsExportAddress(dset, devLsoStdio);
|
||||
|
||||
|
||||
/* printf device support */
|
||||
|
||||
static long add_printf(dbCommon *pcommon) {
|
||||
printfRecord *prec = (printfRecord *) pcommon;
|
||||
struct outStream *pstream;
|
||||
|
||||
if (prec->out.type != INST_IO)
|
||||
return S_dev_badOutType;
|
||||
|
||||
for (pstream = outStreams; pstream->name; ++pstream) {
|
||||
if (strcmp(prec->out.value.instio.string, pstream->name) == 0) {
|
||||
prec->dpvt = pstream;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
prec->dpvt = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static long del_printf(dbCommon *pcommon) {
|
||||
printfRecord *prec = (printfRecord *) pcommon;
|
||||
|
||||
prec->dpvt = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dsxt dsxtPrintfStdio = {
|
||||
add_printf, del_printf
|
||||
};
|
||||
|
||||
static long init_printf(int pass)
|
||||
{
|
||||
if (pass == 0) devExtend(&dsxtPrintfStdio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long write_printf(printfRecord *prec)
|
||||
{
|
||||
struct outStream *pstream = (struct outStream *)prec->dpvt;
|
||||
if (pstream)
|
||||
pstream->print("%s\n", prec->val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printfdset devPrintfStdio = {
|
||||
5, NULL, init_printf, NULL, NULL, write_printf
|
||||
};
|
||||
epicsExportAddress(dset, devPrintfStdio);
|
||||
|
||||
|
||||
/* stringout device support */
|
||||
|
||||
static long add_stringout(dbCommon *pcommon) {
|
||||
stringoutRecord *prec = (stringoutRecord *) pcommon;
|
||||
struct outStream *pstream;
|
||||
|
||||
if (prec->out.type != INST_IO)
|
||||
return S_dev_badOutType;
|
||||
|
||||
for (pstream = outStreams; pstream->name; ++pstream) {
|
||||
if (strcmp(prec->out.value.instio.string, pstream->name) == 0) {
|
||||
prec->dpvt = pstream;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
prec->dpvt = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static long del_stringout(dbCommon *pcommon) {
|
||||
stringoutRecord *prec = (stringoutRecord *) pcommon;
|
||||
|
||||
prec->dpvt = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dsxt dsxtSoStdio = {
|
||||
add_stringout, del_stringout
|
||||
};
|
||||
|
||||
static long init_stringout(int pass)
|
||||
{
|
||||
if (pass == 0) devExtend(&dsxtSoStdio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long write_stringout(stringoutRecord *prec)
|
||||
{
|
||||
struct outStream *pstream = (struct outStream *)prec->dpvt;
|
||||
if (pstream)
|
||||
pstream->print("%s\n", prec->val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct {
|
||||
dset common;
|
||||
DEVSUPFUN write;
|
||||
} devSoStdio = {
|
||||
{5, NULL, init_stringout, NULL, NULL}, write_stringout
|
||||
};
|
||||
epicsExportAddress(dset, devSoStdio);
|
||||
@@ -11,67 +11,43 @@
|
||||
|
||||
SRC_DIRS += $(STDDIR)/rec
|
||||
|
||||
DBDINC += aaiRecord
|
||||
DBDINC += aaoRecord
|
||||
DBDINC += aiRecord
|
||||
DBDINC += aoRecord
|
||||
DBDINC += aSubRecord
|
||||
DBDINC += biRecord
|
||||
DBDINC += boRecord
|
||||
DBDINC += calcRecord
|
||||
DBDINC += calcoutRecord
|
||||
DBDINC += compressRecord
|
||||
DBDINC += dfanoutRecord
|
||||
DBDINC += eventRecord
|
||||
DBDINC += fanoutRecord
|
||||
DBDINC += histogramRecord
|
||||
DBDINC += longinRecord
|
||||
DBDINC += longoutRecord
|
||||
DBDINC += mbbiRecord
|
||||
DBDINC += mbbiDirectRecord
|
||||
DBDINC += mbboRecord
|
||||
DBDINC += mbboDirectRecord
|
||||
DBDINC += permissiveRecord
|
||||
DBDINC += selRecord
|
||||
DBDINC += seqRecord
|
||||
DBDINC += stateRecord
|
||||
DBDINC += stringinRecord
|
||||
DBDINC += stringoutRecord
|
||||
DBDINC += subRecord
|
||||
DBDINC += subArrayRecord
|
||||
DBDINC += waveformRecord
|
||||
stdRecords += aaiRecord
|
||||
stdRecords += aaoRecord
|
||||
stdRecords += aiRecord
|
||||
stdRecords += aoRecord
|
||||
stdRecords += aSubRecord
|
||||
stdRecords += biRecord
|
||||
stdRecords += boRecord
|
||||
stdRecords += calcRecord
|
||||
stdRecords += calcoutRecord
|
||||
stdRecords += compressRecord
|
||||
stdRecords += dfanoutRecord
|
||||
stdRecords += eventRecord
|
||||
stdRecords += fanoutRecord
|
||||
stdRecords += histogramRecord
|
||||
stdRecords += longinRecord
|
||||
stdRecords += longoutRecord
|
||||
stdRecords += lsiRecord
|
||||
stdRecords += lsoRecord
|
||||
stdRecords += mbbiRecord
|
||||
stdRecords += mbbiDirectRecord
|
||||
stdRecords += mbboRecord
|
||||
stdRecords += mbboDirectRecord
|
||||
stdRecords += permissiveRecord
|
||||
stdRecords += printfRecord
|
||||
stdRecords += selRecord
|
||||
stdRecords += seqRecord
|
||||
stdRecords += stateRecord
|
||||
stdRecords += stringinRecord
|
||||
stdRecords += stringoutRecord
|
||||
stdRecords += subRecord
|
||||
stdRecords += subArrayRecord
|
||||
stdRecords += waveformRecord
|
||||
|
||||
DBDINC += $(stdRecords)
|
||||
DBD += stdRecords.dbd
|
||||
|
||||
stdRecords_DBD = $(patsubst %,%.dbd,$(DBDINC))
|
||||
stdRecords_DBD = $(patsubst %,%.dbd,$(stdRecords))
|
||||
|
||||
dbRecStd_SRCS += aaiRecord.c
|
||||
dbRecStd_SRCS += aaoRecord.c
|
||||
dbRecStd_SRCS += aiRecord.c
|
||||
dbRecStd_SRCS += aoRecord.c
|
||||
dbRecStd_SRCS += aSubRecord.c
|
||||
dbRecStd_SRCS += biRecord.c
|
||||
dbRecStd_SRCS += boRecord.c
|
||||
dbRecStd_SRCS += calcRecord.c
|
||||
dbRecStd_SRCS += calcoutRecord.c
|
||||
dbRecStd_SRCS += compressRecord.c
|
||||
dbRecStd_SRCS += dfanoutRecord.c
|
||||
dbRecStd_SRCS += eventRecord.c
|
||||
dbRecStd_SRCS += fanoutRecord.c
|
||||
dbRecStd_SRCS += histogramRecord.c
|
||||
dbRecStd_SRCS += longinRecord.c
|
||||
dbRecStd_SRCS += longoutRecord.c
|
||||
dbRecStd_SRCS += mbbiRecord.c
|
||||
dbRecStd_SRCS += mbbiDirectRecord.c
|
||||
dbRecStd_SRCS += mbboRecord.c
|
||||
dbRecStd_SRCS += mbboDirectRecord.c
|
||||
dbRecStd_SRCS += permissiveRecord.c
|
||||
dbRecStd_SRCS += selRecord.c
|
||||
dbRecStd_SRCS += seqRecord.c
|
||||
dbRecStd_SRCS += stateRecord.c
|
||||
dbRecStd_SRCS += stringinRecord.c
|
||||
dbRecStd_SRCS += stringoutRecord.c
|
||||
dbRecStd_SRCS += subRecord.c
|
||||
dbRecStd_SRCS += subArrayRecord.c
|
||||
dbRecStd_SRCS += waveformRecord.c
|
||||
dbRecStd_SRCS += $(patsubst %,%.c,$(stdRecords))
|
||||
|
||||
|
||||
284
src/std/rec/lsiRecord.c
Normal file
284
src/std/rec/lsiRecord.c
Normal file
@@ -0,0 +1,284 @@
|
||||
/*************************************************************************\
|
||||
* 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 <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
dbLoadLink(&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) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (prec->len) {
|
||||
strcpy(prec->oval, prec->val);
|
||||
prec->olen = prec->len;
|
||||
prec->udf = FALSE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long process(lsiRecord *prec)
|
||||
{
|
||||
int pact = prec->pact;
|
||||
lsidset *pdset = (lsidset *) prec->dset;
|
||||
long status = 0;
|
||||
|
||||
if (!pdset || !pdset->read_string) {
|
||||
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; /* ensure data is terminated */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long special(DBADDR *paddr, int after)
|
||||
{
|
||||
lsiRecord *prec = (lsiRecord *) paddr->precord;
|
||||
|
||||
if (!after)
|
||||
return 0;
|
||||
|
||||
/* We set prec->len here and not in put_array_info()
|
||||
* because that does not get called if the put was
|
||||
* done using a DBR_STRING type.
|
||||
*/
|
||||
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 menuYesNoNO:
|
||||
read:
|
||||
status = pdset->read_string(prec);
|
||||
break;
|
||||
|
||||
case menuYesNoYES:
|
||||
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
|
||||
status = dbGetLinkLS(&prec->siol, prec->val, prec->sizv, &prec->len);
|
||||
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);
|
||||
88
src/std/rec/lsiRecord.dbd
Normal file
88
src/std/rec/lsiRecord.dbd
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
322
src/std/rec/lsoRecord.c
Normal file
322
src/std/rec/lsoRecord.c
Normal file
@@ -0,0 +1,322 @@
|
||||
/*************************************************************************\
|
||||
* 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 Output record type */
|
||||
/*
|
||||
* Author: Andrew Johnson
|
||||
* Date: 2012-11-28
|
||||
*/
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "alarm.h"
|
||||
#include "cantProceed.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbEvent.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "devSup.h"
|
||||
#include "errMdef.h"
|
||||
#include "menuIvoa.h"
|
||||
#include "menuOmsl.h"
|
||||
#include "menuPost.h"
|
||||
#include "menuYesNo.h"
|
||||
#include "recSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "special.h"
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "lsoRecord.h"
|
||||
#undef GEN_SIZE_OFFSET
|
||||
#include "epicsExport.h"
|
||||
|
||||
static void monitor(lsoRecord *);
|
||||
static long writeValue(lsoRecord *);
|
||||
|
||||
static long init_record(lsoRecord *prec, int pass)
|
||||
{
|
||||
lsodset *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, "lso::init_record");
|
||||
prec->len = 0;
|
||||
prec->oval = callocMustSucceed(1, sizv, "lso::init_record");
|
||||
prec->olen = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbLoadLink(&prec->siml, DBF_USHORT, &prec->simm);
|
||||
|
||||
pdset = (lsodset *) prec->dset;
|
||||
if (!pdset) {
|
||||
recGblRecordError(S_dev_noDSET, prec, "lso: init_record");
|
||||
return S_dev_noDSET;
|
||||
}
|
||||
|
||||
/* must have a write_string function defined */
|
||||
if (pdset->number < 5 || !pdset->write_string) {
|
||||
recGblRecordError(S_dev_missingSup, prec, "lso: init_record");
|
||||
return S_dev_missingSup;
|
||||
}
|
||||
|
||||
dbLoadLinkLS(&prec->dol, prec->val, prec->sizv, &prec->len);
|
||||
|
||||
if (pdset->init_record) {
|
||||
long status = pdset->init_record(prec);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (prec->len) {
|
||||
strcpy(prec->oval, prec->val);
|
||||
prec->olen = prec->len;
|
||||
prec->udf = FALSE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long process(lsoRecord *prec)
|
||||
{
|
||||
int pact = prec->pact;
|
||||
lsodset *pdset = (lsodset *) prec->dset;
|
||||
long status = 0;
|
||||
|
||||
if (!pdset || !pdset->write_string) {
|
||||
prec->pact = TRUE;
|
||||
recGblRecordError(S_dev_missingSup, prec, "lso: write_string");
|
||||
return S_dev_missingSup;
|
||||
}
|
||||
|
||||
if (!pact && prec->omsl == menuOmslclosed_loop)
|
||||
if (!dbGetLinkLS(&prec->dol, prec->val, prec->sizv, &prec->len))
|
||||
prec->udf = FALSE;
|
||||
|
||||
if (prec->udf)
|
||||
recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM);
|
||||
|
||||
if (prec->nsev < INVALID_ALARM )
|
||||
status = writeValue(prec); /* write the new value */
|
||||
else {
|
||||
switch (prec->ivoa) {
|
||||
case menuIvoaContinue_normally:
|
||||
status = writeValue(prec); /* write the new value */
|
||||
break;
|
||||
|
||||
case menuIvoaDon_t_drive_outputs:
|
||||
break;
|
||||
|
||||
case menuIvoaSet_output_to_IVOV:
|
||||
if (!prec->pact) {
|
||||
size_t size = prec->sizv - 1;
|
||||
|
||||
strncpy(prec->val, prec->ivov, size);
|
||||
prec->val[size] = 0;
|
||||
prec->len = strlen(prec->val) + 1;
|
||||
}
|
||||
status = writeValue(prec); /* write the new value */
|
||||
break;
|
||||
|
||||
default:
|
||||
status = -1;
|
||||
recGblRecordError(S_db_badField, prec,
|
||||
"lso:process Bad IVOA choice");
|
||||
}
|
||||
}
|
||||
|
||||
/* Asynchronous if device support set pact */
|
||||
if (!pact && prec->pact)
|
||||
return status;
|
||||
|
||||
prec->pact = TRUE;
|
||||
recGblGetTimeStamp(prec);
|
||||
|
||||
monitor(prec);
|
||||
|
||||
/* Wrap up */
|
||||
recGblFwdLink(prec);
|
||||
prec->pact = FALSE;
|
||||
return status;
|
||||
}
|
||||
|
||||
static long cvt_dbaddr(DBADDR *paddr)
|
||||
{
|
||||
lsoRecord *prec = (lsoRecord *) paddr->precord;
|
||||
int fieldIndex = dbGetFieldIndex(paddr);
|
||||
|
||||
if (fieldIndex == lsoRecordVAL) {
|
||||
paddr->pfield = prec->val;
|
||||
paddr->special = SPC_MOD;
|
||||
}
|
||||
else if (fieldIndex == lsoRecordOVAL) {
|
||||
paddr->pfield = prec->oval;
|
||||
paddr->special = SPC_NOMOD;
|
||||
}
|
||||
else {
|
||||
errlogPrintf("lsoRecord::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)
|
||||
{
|
||||
lsoRecord *prec = (lsoRecord *) paddr->precord;
|
||||
int fieldIndex = dbGetFieldIndex(paddr);
|
||||
|
||||
if (fieldIndex == lsoRecordVAL)
|
||||
*no_elements = prec->len;
|
||||
else if (fieldIndex == lsoRecordOVAL)
|
||||
*no_elements = prec->olen;
|
||||
else
|
||||
return -1;
|
||||
|
||||
*offset = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long put_array_info(DBADDR *paddr, long nNew)
|
||||
{
|
||||
lsoRecord *prec = (lsoRecord *) paddr->precord;
|
||||
|
||||
if (nNew == prec->sizv)
|
||||
--nNew; /* truncated string */
|
||||
prec->val[nNew] = 0; /* ensure data is terminated */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long special(DBADDR *paddr, int after)
|
||||
{
|
||||
lsoRecord *prec = (lsoRecord *) paddr->precord;
|
||||
|
||||
if (!after)
|
||||
return 0;
|
||||
|
||||
/* We set prec->len here and not in put_array_info()
|
||||
* because that does not get called if the put was
|
||||
* done using a DBR_STRING type.
|
||||
*/
|
||||
prec->len = strlen(prec->val) + 1;
|
||||
db_post_events(prec, &prec->len, DBE_VALUE | DBE_LOG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void monitor(lsoRecord *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 writeValue(lsoRecord *prec)
|
||||
{
|
||||
long status;
|
||||
lsodset *pdset = (lsodset *) prec->dset;
|
||||
|
||||
if (prec->pact)
|
||||
goto write;
|
||||
|
||||
status = dbGetLink(&prec->siml, DBR_USHORT, &prec->simm, 0, 0);
|
||||
if (status)
|
||||
return(status);
|
||||
|
||||
switch (prec->simm) {
|
||||
case menuYesNoNO:
|
||||
write:
|
||||
status = pdset->write_string(prec);
|
||||
break;
|
||||
|
||||
case menuYesNoYES:
|
||||
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
|
||||
status = dbPutLink(&prec->siol,DBR_STRING, prec->val,1);
|
||||
break;
|
||||
|
||||
default:
|
||||
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
|
||||
status = -1;
|
||||
}
|
||||
|
||||
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 lsoRSET = {
|
||||
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, lsoRSET);
|
||||
112
src/std/rec/lsoRecord.dbd
Normal file
112
src/std/rec/lsoRecord.dbd
Normal file
@@ -0,0 +1,112 @@
|
||||
#*************************************************************************
|
||||
# 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(lso) {
|
||||
include "dbCommon.dbd"
|
||||
%#include "devSup.h"
|
||||
%
|
||||
%/* Declare Device Support Entry Table */
|
||||
%typedef struct lsodset {
|
||||
% long number;
|
||||
% DEVSUPFUN report;
|
||||
% DEVSUPFUN init;
|
||||
% DEVSUPFUN init_record;
|
||||
% DEVSUPFUN get_ioint_info;
|
||||
% DEVSUPFUN write_string;
|
||||
%} lsodset;
|
||||
%
|
||||
field(VAL,DBF_NOACCESS) {
|
||||
prompt("Current Value")
|
||||
asl(ASL0)
|
||||
pp(TRUE)
|
||||
special(SPC_DBADDR)
|
||||
extra("char *val")
|
||||
}
|
||||
field(OVAL,DBF_NOACCESS) {
|
||||
prompt("Previous 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)
|
||||
interest(3)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Link")
|
||||
promptgroup(GUI_OUTPUT)
|
||||
interest(1)
|
||||
}
|
||||
field(IVOA,DBF_MENU) {
|
||||
prompt("INVALID Output Action")
|
||||
promptgroup(GUI_OUTPUT)
|
||||
interest(2)
|
||||
menu(menuIvoa)
|
||||
}
|
||||
field(IVOV,DBF_STRING) {
|
||||
prompt("INVALID Output Value")
|
||||
promptgroup(GUI_OUTPUT)
|
||||
interest(2)
|
||||
size(40)
|
||||
}
|
||||
field(OMSL,DBF_MENU) {
|
||||
prompt("Output Mode Select")
|
||||
promptgroup(GUI_OUTPUT)
|
||||
interest(1)
|
||||
menu(menuOmsl)
|
||||
}
|
||||
field(OUT,DBF_OUTLINK) {
|
||||
prompt("Output Specification")
|
||||
promptgroup(GUI_OUTPUT)
|
||||
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("Sim Mode link")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(1)
|
||||
}
|
||||
field(SIMM,DBF_MENU) {
|
||||
prompt("Simulation Mode")
|
||||
interest(1)
|
||||
menu(menuYesNo)
|
||||
}
|
||||
field(SIMS,DBF_MENU) {
|
||||
prompt("Sim mode Alarm Svrty")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(2)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(SIOL,DBF_OUTLINK) {
|
||||
prompt("Sim Output Specifctn")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(1)
|
||||
}
|
||||
}
|
||||
438
src/std/rec/printfRecord.c
Normal file
438
src/std/rec/printfRecord.c
Normal file
@@ -0,0 +1,438 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/* Printf record type */
|
||||
/*
|
||||
* Author: Andrew Johnson
|
||||
* Date: 2012-09-18
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "alarm.h"
|
||||
#include "cantProceed.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbEvent.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "epicsMath.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "errMdef.h"
|
||||
#include "recSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "special.h"
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "printfRecord.h"
|
||||
#undef GEN_SIZE_OFFSET
|
||||
#include "epicsExport.h"
|
||||
|
||||
|
||||
/* Flag bits */
|
||||
#define F_CHAR 1
|
||||
#define F_SHORT 2
|
||||
#define F_LONG 4
|
||||
#define F_LEFT 8
|
||||
#define F_BADFMT 0x10
|
||||
#define F_BADLNK 0x20
|
||||
#define F_BAD (F_BADFMT | F_BADLNK)
|
||||
|
||||
#define GET_PRINT(VALTYPE, DBRTYPE) \
|
||||
VALTYPE val; \
|
||||
int ok; \
|
||||
\
|
||||
if (plink->type == CONSTANT) \
|
||||
ok = recGblInitConstantLink(plink++, DBRTYPE, &val); \
|
||||
else \
|
||||
ok = ! dbGetLink(plink++, DBRTYPE, &val, 0, 0); \
|
||||
if (ok) \
|
||||
added = epicsSnprintf(pval, vspace + 1, format, val); \
|
||||
else \
|
||||
flags |= F_BADLNK
|
||||
|
||||
static void doPrintf(printfRecord *prec)
|
||||
{
|
||||
const char *pfmt = prec->fmt;
|
||||
DBLINK *plink = &prec->inp0;
|
||||
int linkn = 0;
|
||||
char *pval = prec->val;
|
||||
int vspace = prec->sizv - 1;
|
||||
int ch;
|
||||
|
||||
while (vspace > 0 && (ch = *pfmt++)) {
|
||||
if (ch != '%') {
|
||||
/* Copy literal strings directly into prec->val */
|
||||
*pval++ = ch;
|
||||
--vspace;
|
||||
}
|
||||
else {
|
||||
char format[20];
|
||||
char *pformat = format;
|
||||
int width = 0;
|
||||
int precision = 0;
|
||||
int *pnum = &width;
|
||||
int flags = 0;
|
||||
int added = 0;
|
||||
int cont = 1;
|
||||
|
||||
/* The format directive parsing here is not comprehensive,
|
||||
* in most cases we just copy each directive into format[]
|
||||
* and get epicsSnprintf() do all the work. We do replace
|
||||
* all variable-length field width or precision '*' chars
|
||||
* with an integer read from the next input link, and we
|
||||
* also convert %ls (long string) directives ourself, so
|
||||
* we need to know the width, precision and justification.
|
||||
*/
|
||||
|
||||
*pformat++ = ch; /* '%' */
|
||||
while (cont && (ch = *pfmt++)) {
|
||||
*pformat++ = ch;
|
||||
switch (ch) {
|
||||
case '+': case ' ': case '#':
|
||||
break;
|
||||
case '-':
|
||||
flags |= F_LEFT;
|
||||
break;
|
||||
case '.':
|
||||
pnum = &precision;
|
||||
break;
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
*pnum = *pnum * 10 + ch - '0';
|
||||
break;
|
||||
case '*':
|
||||
if (*pnum) {
|
||||
flags |= F_BADFMT;
|
||||
}
|
||||
else if (linkn++ < PRINTF_NLINKS) {
|
||||
epicsInt16 i;
|
||||
int ok;
|
||||
|
||||
if (plink->type == CONSTANT)
|
||||
ok = recGblInitConstantLink(plink++, DBR_SHORT, &i);
|
||||
else
|
||||
ok = ! dbGetLink(plink++, DBR_SHORT, &i, 0, 0);
|
||||
if (ok) {
|
||||
*pnum = i;
|
||||
added = epicsSnprintf(--pformat, 6, "%d", i);
|
||||
pformat += added;
|
||||
}
|
||||
else /* No more LNKn fields */
|
||||
flags |= F_BADLNK;
|
||||
}
|
||||
else
|
||||
flags |= F_BADLNK;
|
||||
break;
|
||||
case 'h':
|
||||
if (flags & F_SHORT)
|
||||
flags = (flags & ~F_SHORT) | F_CHAR;
|
||||
else
|
||||
flags |= F_SHORT;
|
||||
break;
|
||||
case 'l':
|
||||
flags |= F_LONG;
|
||||
break;
|
||||
default:
|
||||
if (strchr("diouxXeEfFgGcs%", ch) == NULL)
|
||||
flags |= F_BADFMT;
|
||||
cont = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ch) /* End of format string */
|
||||
break;
|
||||
|
||||
if (flags & F_BAD)
|
||||
goto bad_format;
|
||||
|
||||
*pformat = 0; /* Terminate our format string */
|
||||
|
||||
if (width < 0) {
|
||||
width = -width;
|
||||
flags |= F_LEFT;
|
||||
}
|
||||
if (precision < 0)
|
||||
precision = 0;
|
||||
|
||||
if (ch == '%') {
|
||||
added = epicsSnprintf(pval, vspace + 1, format);
|
||||
}
|
||||
else if (linkn++ >= PRINTF_NLINKS) {
|
||||
/* No more LNKn fields */
|
||||
flags |= F_BADLNK;
|
||||
}
|
||||
else
|
||||
switch (ch) { /* Conversion character */
|
||||
case 'c': case 'd': case 'i':
|
||||
if (ch == 'c' || flags & F_CHAR) {
|
||||
GET_PRINT(epicsInt8, DBR_CHAR);
|
||||
}
|
||||
else if (flags & F_SHORT) {
|
||||
GET_PRINT(epicsInt16, DBR_SHORT);
|
||||
}
|
||||
else { /* F_LONG has no real effect */
|
||||
GET_PRINT(epicsInt32, DBR_LONG);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'o': case 'x': case 'X': case 'u':
|
||||
if (flags & F_CHAR) {
|
||||
GET_PRINT(epicsUInt8, DBR_UCHAR);
|
||||
}
|
||||
else if (flags & F_SHORT) {
|
||||
GET_PRINT(epicsUInt16, DBR_USHORT);
|
||||
}
|
||||
else { /* F_LONG has no real effect */
|
||||
GET_PRINT(epicsUInt32, DBR_ULONG);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'e': case 'E':
|
||||
case 'f': case 'F':
|
||||
case 'g': case 'G':
|
||||
if (flags & F_SHORT) {
|
||||
GET_PRINT(epicsFloat32, DBR_FLOAT);
|
||||
}
|
||||
else {
|
||||
GET_PRINT(epicsFloat64, DBR_DOUBLE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (flags & F_LONG && plink->type != CONSTANT) {
|
||||
long n = vspace + 1;
|
||||
|
||||
if (precision && n > precision)
|
||||
n = precision + 1;
|
||||
/* If set, precision is the maximum number of
|
||||
* characters to be printed from the string.
|
||||
* It does not limit the field width however.
|
||||
*/
|
||||
if (dbGetLink(plink++, DBR_CHAR, pval, 0, &n))
|
||||
flags |= F_BADLNK;
|
||||
else {
|
||||
int padding;
|
||||
|
||||
/* Terminate string and measure its length */
|
||||
pval[n] = 0;
|
||||
added = strlen(pval);
|
||||
padding = width - added;
|
||||
|
||||
if (padding > 0) {
|
||||
if (flags & F_LEFT) {
|
||||
/* add spaces on RHS */
|
||||
if (width > vspace)
|
||||
padding = vspace - added;
|
||||
memset(pval + added, ' ', padding);
|
||||
}
|
||||
else {
|
||||
/* insert spaces on LHS */
|
||||
int trunc = width - vspace;
|
||||
|
||||
if (trunc < added) {
|
||||
added -= trunc;
|
||||
memmove(pval + padding, pval, added);
|
||||
}
|
||||
else {
|
||||
padding = vspace;
|
||||
added = 0;
|
||||
}
|
||||
memset(pval, ' ', padding);
|
||||
}
|
||||
added += padding;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
char val[MAX_STRING_SIZE];
|
||||
int ok;
|
||||
|
||||
if (plink->type == CONSTANT)
|
||||
ok = recGblInitConstantLink(plink++, DBR_STRING, val);
|
||||
else
|
||||
ok = ! dbGetLink(plink++, DBR_STRING, val, 0, 0);
|
||||
if (ok)
|
||||
added = epicsSnprintf(pval, vspace + 1, format, val);
|
||||
else
|
||||
flags |= F_BADLNK;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
errlogPrintf("printfRecord: Unexpected conversion '%s'\n",
|
||||
format);
|
||||
flags |= F_BADFMT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags & F_BAD) {
|
||||
bad_format:
|
||||
added = epicsSnprintf(pval, vspace + 1, "%s",
|
||||
flags & F_BADLNK ? prec->ivls : format);
|
||||
}
|
||||
|
||||
if (added <= vspace) {
|
||||
pval += added;
|
||||
vspace -= added;
|
||||
}
|
||||
else {
|
||||
/* Output was truncated */
|
||||
pval += vspace;
|
||||
vspace = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
*pval++ = 0; /* Terminate the VAL string */
|
||||
prec->len = pval - prec->val;
|
||||
}
|
||||
|
||||
|
||||
static long init_record(printfRecord *prec, int pass)
|
||||
{
|
||||
printfdset *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, "printf::init_record");
|
||||
prec->len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pdset = (printfdset *) prec->dset;
|
||||
if (!pdset)
|
||||
return 0; /* Device support is optional */
|
||||
|
||||
if (pdset->number < 5) {
|
||||
recGblRecordError(S_dev_missingSup, prec, "printf::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(printfRecord *prec)
|
||||
{
|
||||
int pact = prec->pact;
|
||||
printfdset *pdset;
|
||||
long status = 0;
|
||||
epicsUInt16 events;
|
||||
|
||||
if (!pact) {
|
||||
doPrintf(prec);
|
||||
|
||||
prec->udf = FALSE;
|
||||
recGblGetTimeStamp(prec);
|
||||
}
|
||||
|
||||
/* Call device support */
|
||||
pdset = (printfdset *) prec->dset;
|
||||
if (pdset &&
|
||||
pdset->number >= 5 &&
|
||||
pdset->write_string) {
|
||||
status = pdset->write_string(prec);
|
||||
|
||||
/* Asynchronous if device support set pact */
|
||||
if (!pact && prec->pact)
|
||||
return status;
|
||||
}
|
||||
|
||||
prec->pact = TRUE;
|
||||
|
||||
/* Post monitor */
|
||||
events = recGblResetAlarms(prec);
|
||||
db_post_events(prec, prec->val, events | DBE_VALUE | DBE_LOG);
|
||||
db_post_events(prec, &prec->len, events | DBE_VALUE | DBE_LOG);
|
||||
|
||||
/* Wrap up */
|
||||
recGblFwdLink(prec);
|
||||
prec->pact = FALSE;
|
||||
return status;
|
||||
}
|
||||
|
||||
static long cvt_dbaddr(DBADDR *paddr)
|
||||
{
|
||||
printfRecord *prec = (printfRecord *)paddr->precord;
|
||||
int fieldIndex = dbGetFieldIndex(paddr);
|
||||
|
||||
if (fieldIndex == printfRecordVAL) {
|
||||
paddr->pfield = prec->val;
|
||||
paddr->no_elements = 1;
|
||||
paddr->field_type = DBF_STRING;
|
||||
paddr->dbr_field_type = DBF_STRING;
|
||||
paddr->field_size = prec->sizv;
|
||||
}
|
||||
else
|
||||
errlogPrintf("printfRecord::cvt_dbaddr called for %s.%s\n",
|
||||
prec->name, paddr->pfldDes->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
|
||||
{
|
||||
printfRecord *prec = (printfRecord *) paddr->precord;
|
||||
|
||||
*no_elements = prec->len;
|
||||
*offset = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Create Record Support Entry Table */
|
||||
|
||||
#define report NULL
|
||||
#define initialize NULL
|
||||
/* init_record */
|
||||
/* process */
|
||||
#define special NULL
|
||||
#define get_value NULL
|
||||
/* cvt_dbaddr */
|
||||
/* get_array_info */
|
||||
#define put_array_info NULL
|
||||
#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 printfRSET = {
|
||||
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, printfRSET);
|
||||
|
||||
109
src/std/rec/printfRecord.dbd
Normal file
109
src/std/rec/printfRecord.dbd
Normal file
@@ -0,0 +1,109 @@
|
||||
#*************************************************************************
|
||||
# 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(printf) {
|
||||
include "dbCommon.dbd"
|
||||
%#include "devSup.h"
|
||||
%
|
||||
%/* Declare Device Support Entry Table */
|
||||
%typedef struct printfdset {
|
||||
% long number;
|
||||
% DEVSUPFUN report;
|
||||
% DEVSUPFUN init;
|
||||
% DEVSUPFUN init_record;
|
||||
% DEVSUPFUN get_ioint_info;
|
||||
% DEVSUPFUN write_string;
|
||||
%} printfdset;
|
||||
%
|
||||
field(VAL,DBF_NOACCESS) {
|
||||
prompt("Result")
|
||||
asl(ASL0)
|
||||
pp(TRUE)
|
||||
special(SPC_DBADDR)
|
||||
extra("char *val")
|
||||
}
|
||||
field(SIZV,DBF_USHORT) {
|
||||
prompt("Size of VAL buffer")
|
||||
promptgroup(GUI_OUTPUT)
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
initial("41")
|
||||
}
|
||||
field(LEN,DBF_ULONG) {
|
||||
prompt("Length of VAL")
|
||||
special(SPC_NOMOD)
|
||||
}
|
||||
field(OUT,DBF_OUTLINK) {
|
||||
prompt("Output Specification")
|
||||
promptgroup(GUI_OUTPUT)
|
||||
interest(1)
|
||||
}
|
||||
field(FMT,DBF_STRING) {
|
||||
prompt("Format String")
|
||||
promptgroup(GUI_CALC)
|
||||
pp(TRUE)
|
||||
size(81)
|
||||
}
|
||||
field(IVLS,DBF_STRING) {
|
||||
prompt("Invalid Link String")
|
||||
promptgroup(GUI_CALC)
|
||||
size(16)
|
||||
initial("LNK")
|
||||
}
|
||||
field(INP0,DBF_INLINK) {
|
||||
prompt("Input 0")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(1)
|
||||
}
|
||||
field(INP1,DBF_INLINK) {
|
||||
prompt("Input 1")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(1)
|
||||
}
|
||||
field(INP2,DBF_INLINK) {
|
||||
prompt("Input 2")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(1)
|
||||
}
|
||||
field(INP3,DBF_INLINK) {
|
||||
prompt("Input 3")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(1)
|
||||
}
|
||||
field(INP4,DBF_INLINK) {
|
||||
prompt("Input 4")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(1)
|
||||
}
|
||||
field(INP5,DBF_INLINK) {
|
||||
prompt("Input 5")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(1)
|
||||
}
|
||||
field(INP6,DBF_INLINK) {
|
||||
prompt("Input 6")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(1)
|
||||
}
|
||||
field(INP7,DBF_INLINK) {
|
||||
prompt("Input 7")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(1)
|
||||
}
|
||||
field(INP8,DBF_INLINK) {
|
||||
prompt("Input 8")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(1)
|
||||
}
|
||||
field(INP9,DBF_INLINK) {
|
||||
prompt("Input 9")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(1)
|
||||
}
|
||||
%/* Number of INPx fields defined */
|
||||
%#define PRINTF_NLINKS 10
|
||||
}
|
||||
Reference in New Issue
Block a user