Merged printf-record branch

Adds three new record types: printf, lsi and lso.
Provides device support for all three.
This commit is contained in:
Andrew Johnson
2013-10-03 14:04:03 -07:00
21 changed files with 1919 additions and 201 deletions

View File

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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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
View 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")
}

View File

@@ -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
View 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
View 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);

View 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);

View 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);

View 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);

View File

@@ -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);

View File

@@ -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
View 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);

View File

@@ -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
View 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
View 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
View 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
View 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
View 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);

View 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
}