EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  <20122013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  <20122013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: [Merge] lp:~epics-core/epics-base/printf-record into lp:epics-base
From: Andrew Johnson <[email protected]>
To: [email protected]
Date: Mon, 10 Dec 2012 21:22:20 -0000
Andrew Johnson has proposed merging lp:~epics-core/epics-base/printf-record into lp:epics-base.

Requested reviews:
  EPICS Core Developers (epics-core)

For more details, see:
https://code.launchpad.net/~epics-core/epics-base/printf-record/+merge/139098

This branch adds three new record types and associated device support to Base:
 * printf: A string conversion record, plus device support for Soft Channel, Async Soft Channel and stdio device types.
 * lsi: A long string input record, plus device support for Soft Channel input.
 * lso: A long string output record, plus device support for Soft Channel, Async Soft Channel and stdio device types.
-- 
https://code.launchpad.net/~epics-core/epics-base/printf-record/+merge/139098
Your team EPICS Core Developers is requested to review the proposed merge of lp:~epics-core/epics-base/printf-record into lp:epics-base.
=== modified file 'src/ioc/db/Makefile'
--- src/ioc/db/Makefile	2012-06-21 20:27:32 +0000
+++ src/ioc/db/Makefile	2012-12-10 21:21:25 +0000
@@ -47,6 +47,7 @@
 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

=== modified file 'src/ioc/db/dbAccess.c'
--- src/ioc/db/dbAccess.c	2012-10-29 06:20:56 +0000
+++ src/ioc/db/dbAccess.c	2012-12-10 21:21:25 +0000
@@ -583,10 +583,8 @@
 {
     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 @@
         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;
-
-    dbfType = pflddes->field_type;
-    dbrType = mapDBFToDBR[dbfType];
-    field_size = pflddes->size;
-
+    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];
+
+    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;
@@ -817,7 +816,7 @@
 
     /* 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) {
@@ -1171,7 +1170,7 @@
         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;
 
@@ -1184,7 +1183,7 @@
 
         /* 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);
         }

=== modified file 'src/ioc/db/dbLink.c'
--- src/ioc/db/dbLink.c	2012-07-07 20:54:31 +0000
+++ src/ioc/db/dbLink.c	2012-12-10 21:21:25 +0000
@@ -649,3 +649,62 @@
     }
 }
 
+/* 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);
+}
+

=== modified file 'src/ioc/db/dbLink.h'
--- src/ioc/db/dbLink.h	2012-08-08 18:38:21 +0000
+++ src/ioc/db/dbLink.h	2012-12-10 21:21:25 +0000
@@ -81,6 +81,13 @@
         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

=== added file 'src/ioc/db/menuPost.dbd'
--- src/ioc/db/menuPost.dbd	1970-01-01 00:00:00 +0000
+++ src/ioc/db/menuPost.dbd	2012-12-10 21:21:25 +0000
@@ -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")
+}

=== modified file 'src/std/dev/Makefile'
--- src/std/dev/Makefile	2012-07-11 23:07:23 +0000
+++ src/std/dev/Makefile	2012-12-10 21:21:25 +0000
@@ -30,6 +30,8 @@
 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 += 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 += 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
 

=== added file 'src/std/dev/devLsiSoft.c'
--- src/std/dev/devLsiSoft.c	1970-01-01 00:00:00 +0000
+++ src/std/dev/devLsiSoft.c	2012-12-10 21:21:25 +0000
@@ -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);

=== added file 'src/std/dev/devLsoSoft.c'
--- src/std/dev/devLsoSoft.c	1970-01-01 00:00:00 +0000
+++ src/std/dev/devLsoSoft.c	2012-12-10 21:21:25 +0000
@@ -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);

=== added file 'src/std/dev/devLsoSoftCallback.c'
--- src/std/dev/devLsoSoftCallback.c	1970-01-01 00:00:00 +0000
+++ src/std/dev/devLsoSoftCallback.c	2012-12-10 21:21:25 +0000
@@ -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);

=== added file 'src/std/dev/devPrintfSoft.c'
--- src/std/dev/devPrintfSoft.c	1970-01-01 00:00:00 +0000
+++ src/std/dev/devPrintfSoft.c	2012-12-10 21:21:25 +0000
@@ -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);
+

=== added file 'src/std/dev/devPrintfSoftCallback.c'
--- src/std/dev/devPrintfSoftCallback.c	1970-01-01 00:00:00 +0000
+++ src/std/dev/devPrintfSoftCallback.c	2012-12-10 21:21:25 +0000
@@ -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);

=== removed file 'src/std/dev/devSoStdio.c'
--- src/std/dev/devSoStdio.c	2012-07-18 21:45:23 +0000
+++ src/std/dev/devSoStdio.c	1970-01-01 00:00:00 +0000
@@ -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);

=== modified file 'src/std/dev/devSoft.dbd'
--- src/std/dev/devSoft.dbd	2012-07-11 23:07:23 +0000
+++ src/std/dev/devSoft.dbd	2012-12-10 21:21:25 +0000
@@ -9,10 +9,13 @@
 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(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(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")

=== added file 'src/std/dev/devStdio.c'
--- src/std/dev/devStdio.c	1970-01-01 00:00:00 +0000
+++ src/std/dev/devStdio.c	2012-12-10 21:21:25 +0000
@@ -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);

=== modified file 'src/std/rec/Makefile'
--- src/std/rec/Makefile	2011-11-14 23:42:50 +0000
+++ src/std/rec/Makefile	2012-12-10 21:21:25 +0000
@@ -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))
 

=== modified file 'src/std/rec/RULES'
--- src/std/rec/RULES	2011-02-27 00:24:51 +0000
+++ src/std/rec/RULES	2012-12-10 21:21:25 +0000
@@ -9,7 +9,7 @@
 
 # This is a Makefile fragment, see src/std/Makefile.
 
-$(COMMON_DIR)/stdRecords.dbd:
+$(COMMON_DIR)/stdRecords.dbd: ../rec/Makefile
 	$(RM) $@
 	$(PERL) $(TOOLS)/makeIncludeDbd.pl $(stdRecords_DBD) $@
 

=== added file 'src/std/rec/lsiRecord.c'
--- src/std/rec/lsiRecord.c	1970-01-01 00:00:00 +0000
+++ src/std/rec/lsiRecord.c	2012-12-10 21:21:25 +0000
@@ -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);

=== added file 'src/std/rec/lsiRecord.dbd'
--- src/std/rec/lsiRecord.dbd	1970-01-01 00:00:00 +0000
+++ src/std/rec/lsiRecord.dbd	2012-12-10 21:21:25 +0000
@@ -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)
+    }
+}

=== added file 'src/std/rec/lsoRecord.c'
--- src/std/rec/lsoRecord.c	1970-01-01 00:00:00 +0000
+++ src/std/rec/lsoRecord.c	2012-12-10 21:21:25 +0000
@@ -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);

=== added file 'src/std/rec/lsoRecord.dbd'
--- src/std/rec/lsoRecord.dbd	1970-01-01 00:00:00 +0000
+++ src/std/rec/lsoRecord.dbd	2012-12-10 21:21:25 +0000
@@ -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)
+    }
+}

=== added file 'src/std/rec/printfRecord.c'
--- src/std/rec/printfRecord.c	1970-01-01 00:00:00 +0000
+++ src/std/rec/printfRecord.c	2012-12-10 21:21:25 +0000
@@ -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);
+

=== added file 'src/std/rec/printfRecord.dbd'
--- src/std/rec/printfRecord.dbd	1970-01-01 00:00:00 +0000
+++ src/std/rec/printfRecord.dbd	2012-12-10 21:21:25 +0000
@@ -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
+}


Navigate by Date:
Prev: Re: [Merge] lp:~anj/epics-base/udf-severity into lp:epics-base Ben Franksen
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  <20122013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: [Merge] lp:~anj/epics-base/udf-severity into lp:epics-base Ben Franksen
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  <20122013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 10 Dec 2012 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·