Merge lp:~epics-core/epics-base/printf-record into lp:~epics-core/epics-base/3.15

Proposed by Andrew Johnson
Status: Merged
Merged at revision: 12444
Proposed branch: lp:~epics-core/epics-base/printf-record
Merge into: lp:~epics-core/epics-base/3.15
Diff against target: 2365 lines (+1922/-204)
22 files modified
src/ioc/db/Makefile (+1/-0)
src/ioc/db/dbAccess.c (+34/-35)
src/ioc/db/dbLink.c (+59/-0)
src/ioc/db/dbLink.h (+7/-0)
src/ioc/db/menuPost.dbd (+11/-0)
src/std/dev/Makefile (+6/-1)
src/std/dev/devLsiSoft.c (+42/-0)
src/std/dev/devLsoSoft.c (+26/-0)
src/std/dev/devLsoSoftCallback.c (+51/-0)
src/std/dev/devPrintfSoft.c (+26/-0)
src/std/dev/devPrintfSoftCallback.c (+51/-0)
src/std/dev/devSoStdio.c (+0/-108)
src/std/dev/devSoft.dbd (+7/-0)
src/std/dev/devStdio.c (+212/-0)
src/std/rec/Makefile (+35/-59)
src/std/rec/RULES (+1/-1)
src/std/rec/lsiRecord.c (+284/-0)
src/std/rec/lsiRecord.dbd (+88/-0)
src/std/rec/lsoRecord.c (+322/-0)
src/std/rec/lsoRecord.dbd (+112/-0)
src/std/rec/printfRecord.c (+438/-0)
src/std/rec/printfRecord.dbd (+109/-0)
To merge this branch: bzr merge lp:~epics-core/epics-base/printf-record
Reviewer Review Type Date Requested Status
Andrew Johnson Approve
Review via email: mp+139098@code.launchpad.net

Description of the change

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.

To post a comment you must log in.
Revision history for this message
Andrew Johnson (anj) wrote :

Nobody seems to care, so I'm merging this.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/ioc/db/Makefile'
2--- src/ioc/db/Makefile 2012-06-21 20:27:32 +0000
3+++ src/ioc/db/Makefile 2012-12-10 21:21:25 +0000
4@@ -47,6 +47,7 @@
5 menuGlobal_DBD += menuIvoa.dbd
6 menuGlobal_DBD += menuOmsl.dbd
7 menuGlobal_DBD += menuPini.dbd
8+menuGlobal_DBD += menuPost.dbd
9 menuGlobal_DBD += menuPriority.dbd
10 menuGlobal_DBD += menuScan.dbd
11 menuGlobal_DBD += menuYesNo.dbd
12
13=== modified file 'src/ioc/db/dbAccess.c'
14--- src/ioc/db/dbAccess.c 2012-10-29 06:20:56 +0000
15+++ src/ioc/db/dbAccess.c 2012-12-10 21:21:25 +0000
16@@ -583,10 +583,8 @@
17 {
18 DBENTRY dbEntry;
19 dbFldDes *pflddes;
20- struct rset *prset;
21 long status = 0;
22- long no_elements = 1;
23- short dbfType, dbrType, field_size;
24+ short dbfType;
25
26 if (!pname || !*pname || !pdbbase)
27 return S_db_notFound;
28@@ -601,48 +599,49 @@
29 status = dbGetAttributePart(&dbEntry, &pname);
30 if (status) goto finish;
31
32+ pflddes = dbEntry.pflddes;
33+ dbfType = pflddes->field_type;
34+
35 paddr->precord = dbEntry.precnode->precord;
36 paddr->pfield = dbEntry.pfield;
37- pflddes = dbEntry.pflddes;
38-
39- dbfType = pflddes->field_type;
40- dbrType = mapDBFToDBR[dbfType];
41- field_size = pflddes->size;
42-
43+ paddr->pfldDes = pflddes;
44+ paddr->no_elements = 1;
45+ paddr->field_type = dbfType;
46+ paddr->field_size = pflddes->size;
47+ paddr->special = pflddes->special;
48+ paddr->dbr_field_type = mapDBFToDBR[dbfType];
49+
50+ if (paddr->special == SPC_DBADDR) {
51+ struct rset *prset = dbGetRset(paddr);
52+
53+ /* Let record type modify paddr */
54+ if (prset && prset->cvt_dbaddr) {
55+ status = prset->cvt_dbaddr(paddr);
56+ if (status)
57+ goto finish;
58+ dbfType = paddr->field_type;
59+ }
60+ }
61+
62+ /* Handle field modifiers */
63 if (*pname++ == '$') {
64 /* Some field types can be accessed as char arrays */
65 if (dbfType == DBF_STRING) {
66- dbfType = DBF_CHAR;
67- dbrType = DBR_CHAR;
68- no_elements = field_size;
69- field_size = 1;
70+ paddr->no_elements = paddr->field_size;
71+ paddr->field_type = DBF_CHAR;
72+ paddr->field_size = 1;
73+ paddr->dbr_field_type = DBR_CHAR;
74 } else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
75 /* Clients see a char array, but keep original dbfType */
76- dbrType = DBR_CHAR;
77- no_elements = PVNAME_STRINGSZ + 12;
78- field_size = 1;
79+ paddr->no_elements = PVNAME_STRINGSZ + 12;
80+ paddr->field_size = 1;
81+ paddr->dbr_field_type = DBR_CHAR;
82 } else {
83 status = S_dbLib_fieldNotFound;
84 goto finish;
85 }
86 }
87
88- paddr->pfldDes = pflddes;
89- paddr->field_type = dbfType;
90- paddr->dbr_field_type = dbrType;
91- paddr->field_size = field_size;
92- paddr->special = pflddes->special;
93- paddr->no_elements = no_elements;
94-
95- if ((paddr->special == SPC_DBADDR) &&
96- (prset = dbGetRset(paddr)) &&
97- prset->cvt_dbaddr)
98- /* cvt_dbaddr routine may change any of these elements of paddr:
99- * pfield, no_elements, element_offset, field_type,
100- * dbr_field_type, field_size, and/or special.
101- */
102- status = prset->cvt_dbaddr(paddr);
103-
104 finish:
105 dbFinishEntry(&dbEntry);
106 return status;
107@@ -817,7 +816,7 @@
108
109 /* check for array */
110 if ((!pfl || pfl->type == dbfl_type_rec) &&
111- paddr->special == SPC_DBADDR &&
112+ paddr->pfldDes->special == SPC_DBADDR &&
113 no_elements > 1 &&
114 (prset = dbGetRset(paddr)) &&
115 prset->get_array_info) {
116@@ -1171,7 +1170,7 @@
117 struct rset *prset = dbGetRset(paddr);
118 long offset = 0;
119
120- if (paddr->special == SPC_DBADDR &&
121+ if (paddr->pfldDes->special == SPC_DBADDR &&
122 prset && prset->get_array_info) {
123 long dummy;
124
125@@ -1184,7 +1183,7 @@
126
127 /* update array info */
128 if (!status &&
129- paddr->special == SPC_DBADDR &&
130+ paddr->pfldDes->special == SPC_DBADDR &&
131 prset && prset->put_array_info) {
132 status = prset->put_array_info(paddr, nRequest);
133 }
134
135=== modified file 'src/ioc/db/dbLink.c'
136--- src/ioc/db/dbLink.c 2012-07-07 20:54:31 +0000
137+++ src/ioc/db/dbLink.c 2012-12-10 21:21:25 +0000
138@@ -649,3 +649,62 @@
139 }
140 }
141
142+/* Helper functions for long string support */
143+
144+long dbLoadLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
145+ epicsUInt32 *plen)
146+{
147+ if (plink->type == CONSTANT &&
148+ plink->value.constantStr) {
149+ strncpy(pbuffer, plink->value.constantStr, --size);
150+ pbuffer[size] = 0;
151+ *plen = strlen(pbuffer) + 1;
152+ return 0;
153+ }
154+
155+ return S_db_notFound;
156+}
157+
158+long dbGetLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
159+ epicsUInt32 *plen)
160+{
161+ int dtyp = dbGetLinkDBFtype(plink);
162+ long len = size;
163+ long status;
164+
165+ if (dtyp < 0) /* Not connected */
166+ return 0;
167+
168+ if (dtyp == DBR_CHAR || dtyp == DBF_UCHAR) {
169+ status = dbGetLink(plink, dtyp, pbuffer, 0, &len);
170+ }
171+ else if (size >= MAX_STRING_SIZE)
172+ status = dbGetLink(plink, DBR_STRING, pbuffer, 0, 0);
173+ else {
174+ /* pbuffer is too small to fetch using DBR_STRING */
175+ char tmp[MAX_STRING_SIZE];
176+
177+ status = dbGetLink(plink, DBR_STRING, tmp, 0, 0);
178+ if (!status)
179+ strncpy(pbuffer, tmp, len - 1);
180+ }
181+ if (!status) {
182+ pbuffer[--len] = 0;
183+ *plen = strlen(pbuffer) + 1;
184+ }
185+ return status;
186+}
187+
188+long dbPutLinkLS(struct link *plink, char *pbuffer, epicsUInt32 len)
189+{
190+ int dtyp = dbGetLinkDBFtype(plink);
191+
192+ if (dtyp < 0)
193+ return 0; /* Not connected */
194+
195+ if (dtyp == DBR_CHAR || dtyp == DBF_UCHAR)
196+ return dbPutLink(plink, dtyp, pbuffer, len);
197+
198+ return dbPutLink(plink, DBR_STRING, pbuffer, 1);
199+}
200+
201
202=== modified file 'src/ioc/db/dbLink.h'
203--- src/ioc/db/dbLink.h 2012-08-08 18:38:21 +0000
204+++ src/ioc/db/dbLink.h 2012-12-10 21:21:25 +0000
205@@ -81,6 +81,13 @@
206 const void *pbuffer, long nRequest);
207 epicsShareFunc void dbScanFwdLink(struct link *plink);
208
209+epicsShareFunc long dbLoadLinkLS(struct link *plink, char *pbuffer,
210+ epicsUInt32 size, epicsUInt32 *plen);
211+epicsShareFunc long dbGetLinkLS(struct link *plink, char *pbuffer,
212+ epicsUInt32 buffer_size, epicsUInt32 *plen);
213+epicsShareFunc long dbPutLinkLS(struct link *plink, char *pbuffer,
214+ epicsUInt32 len);
215+
216 #ifdef __cplusplus
217 }
218 #endif
219
220=== added file 'src/ioc/db/menuPost.dbd'
221--- src/ioc/db/menuPost.dbd 1970-01-01 00:00:00 +0000
222+++ src/ioc/db/menuPost.dbd 2012-12-10 21:21:25 +0000
223@@ -0,0 +1,11 @@
224+#*************************************************************************
225+# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
226+# National Laboratory.
227+# EPICS BASE is distributed subject to a Software License Agreement found
228+# in file LICENSE that is included with this distribution.
229+#*************************************************************************
230+
231+menu(menuPost) {
232+ choice(menuPost_OnChange, "On Change")
233+ choice(menuPost_Always, "Always")
234+}
235
236=== modified file 'src/std/dev/Makefile'
237--- src/std/dev/Makefile 2012-07-11 23:07:23 +0000
238+++ src/std/dev/Makefile 2012-12-10 21:21:25 +0000
239@@ -30,6 +30,8 @@
240 dbRecStd_SRCS += devHistogramSoft.c
241 dbRecStd_SRCS += devLiSoft.c
242 dbRecStd_SRCS += devLoSoft.c
243+dbRecStd_SRCS += devLsiSoft.c
244+dbRecStd_SRCS += devLsoSoft.c
245 dbRecStd_SRCS += devMbbiDirectSoft.c
246 dbRecStd_SRCS += devMbbiDirectSoftRaw.c
247 dbRecStd_SRCS += devMbbiSoft.c
248@@ -38,6 +40,7 @@
249 dbRecStd_SRCS += devMbboDirectSoftRaw.c
250 dbRecStd_SRCS += devMbboSoft.c
251 dbRecStd_SRCS += devMbboSoftRaw.c
252+dbRecStd_SRCS += devPrintfSoft.c
253 dbRecStd_SRCS += devSASoft.c
254 dbRecStd_SRCS += devSiSoft.c
255 dbRecStd_SRCS += devSoSoft.c
256@@ -55,12 +58,14 @@
257 dbRecStd_SRCS += devBoSoftCallback.c
258 dbRecStd_SRCS += devCalcoutSoftCallback.c
259 dbRecStd_SRCS += devLoSoftCallback.c
260+dbRecStd_SRCS += devLsoSoftCallback.c
261 dbRecStd_SRCS += devMbboSoftCallback.c
262 dbRecStd_SRCS += devMbboDirectSoftCallback.c
263+dbRecStd_SRCS += devPrintfSoftCallback.c
264 dbRecStd_SRCS += devSoSoftCallback.c
265
266 dbRecStd_SRCS += devTimestamp.c
267-dbRecStd_SRCS += devSoStdio.c
268+dbRecStd_SRCS += devStdio.c
269
270 dbRecStd_SRCS += asSubRecordFunctions.c
271
272
273=== added file 'src/std/dev/devLsiSoft.c'
274--- src/std/dev/devLsiSoft.c 1970-01-01 00:00:00 +0000
275+++ src/std/dev/devLsiSoft.c 2012-12-10 21:21:25 +0000
276@@ -0,0 +1,42 @@
277+/*************************************************************************\
278+* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
279+* National Laboratory.
280+* EPICS BASE is distributed subject to a Software License Agreement found
281+* in file LICENSE that is included with this distribution.
282+\*************************************************************************/
283+
284+/* Long String Input soft device support
285+ *
286+ * Author: Andrew Johnson
287+ * Date: 2012-11-28
288+ */
289+
290+#include "dbAccess.h"
291+#include "epicsTime.h"
292+#include "link.h"
293+#include "lsiRecord.h"
294+#include "epicsExport.h"
295+
296+static long init_record(lsiRecord *prec)
297+{
298+ dbLoadLinkLS(&prec->inp, prec->val, prec->sizv, &prec->len);
299+
300+ return 0;
301+}
302+
303+static long read_string(lsiRecord *prec)
304+{
305+ long status = dbGetLinkLS(&prec->inp, prec->val, prec->sizv, &prec->len);
306+
307+ if (!status &&
308+ prec->tsel.type == CONSTANT &&
309+ prec->tse == epicsTimeEventDeviceTime)
310+ dbGetTimeStamp(&prec->inp, &prec->time);
311+
312+ return status;
313+}
314+
315+lsidset devLsiSoft = {
316+ 5, NULL, NULL, init_record, NULL, read_string
317+};
318+epicsExportAddress(dset, devLsiSoft);
319
320=== added file 'src/std/dev/devLsoSoft.c'
321--- src/std/dev/devLsoSoft.c 1970-01-01 00:00:00 +0000
322+++ src/std/dev/devLsoSoft.c 2012-12-10 21:21:25 +0000
323@@ -0,0 +1,26 @@
324+/*************************************************************************\
325+* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
326+* National Laboratory.
327+* EPICS BASE is distributed subject to a Software License Agreement found
328+* in file LICENSE that is included with this distribution.
329+\*************************************************************************/
330+
331+/* Long String Output soft device support
332+ *
333+ * Author: Andrew Johnson
334+ * Date: 2012-11-29
335+ */
336+
337+#include "dbAccess.h"
338+#include "lsoRecord.h"
339+#include "epicsExport.h"
340+
341+static long write_string(lsoRecord *prec)
342+{
343+ return dbPutLinkLS(&prec->out, prec->val, prec->len);
344+}
345+
346+lsodset devLsoSoft = {
347+ 5, NULL, NULL, NULL, NULL, write_string
348+};
349+epicsExportAddress(dset, devLsoSoft);
350
351=== added file 'src/std/dev/devLsoSoftCallback.c'
352--- src/std/dev/devLsoSoftCallback.c 1970-01-01 00:00:00 +0000
353+++ src/std/dev/devLsoSoftCallback.c 2012-12-10 21:21:25 +0000
354@@ -0,0 +1,51 @@
355+/*************************************************************************\
356+* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
357+* National Laboratory.
358+* EPICS BASE is distributed subject to a Software License Agreement found
359+* in file LICENSE that is included with this distribution.
360+\*************************************************************************/
361+/* $Revision-Id$ */
362+/*
363+ * Author: Andrew Johnson
364+ * Date: 30 Nov 2012
365+ */
366+
367+#include "alarm.h"
368+#include "dbAccess.h"
369+#include "recGbl.h"
370+#include "lsoRecord.h"
371+#include "epicsExport.h"
372+
373+static long write_string(lsoRecord *prec)
374+{
375+ struct link *plink = &prec->out;
376+ int dtyp = dbGetLinkDBFtype(plink);
377+ long len = prec->len;
378+ long status;
379+
380+ if (prec->pact || dtyp < 0)
381+ return 0;
382+
383+ if (dtyp != DBR_CHAR && dtyp != DBF_UCHAR) {
384+ dtyp = DBR_STRING;
385+ len = 1;
386+ }
387+
388+ if (plink->type != CA_LINK)
389+ return dbPutLink(plink, dtyp, prec->val, len);
390+
391+ status = dbCaPutLinkCallback(plink, dtyp, prec->val, len,
392+ dbCaCallbackProcess, plink);
393+ if (status) {
394+ recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
395+ return status;
396+ }
397+
398+ prec->pact = TRUE;
399+ return 0;
400+}
401+
402+lsodset devLsoSoftCallback = {
403+ 5, NULL, NULL, NULL, NULL, write_string
404+};
405+epicsExportAddress(dset, devLsoSoftCallback);
406
407=== added file 'src/std/dev/devPrintfSoft.c'
408--- src/std/dev/devPrintfSoft.c 1970-01-01 00:00:00 +0000
409+++ src/std/dev/devPrintfSoft.c 2012-12-10 21:21:25 +0000
410@@ -0,0 +1,26 @@
411+/*************************************************************************\
412+* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
413+* National Laboratory.
414+* EPICS BASE is distributed subject to a Software License Agreement found
415+* in file LICENSE that is included with this distribution.
416+\*************************************************************************/
417+/* $Revision-Id$ */
418+/*
419+ * Author: Andrew Johnson
420+ * Date: 28 Sept 2012
421+ */
422+
423+#include "dbAccess.h"
424+#include "printfRecord.h"
425+#include "epicsExport.h"
426+
427+static long write_string(printfRecord *prec)
428+{
429+ return dbPutLinkLS(&prec->out, prec->val, prec->len);
430+}
431+
432+printfdset devPrintfSoft = {
433+ 5, NULL, NULL, NULL, NULL, write_string
434+};
435+epicsExportAddress(dset, devPrintfSoft);
436+
437
438=== added file 'src/std/dev/devPrintfSoftCallback.c'
439--- src/std/dev/devPrintfSoftCallback.c 1970-01-01 00:00:00 +0000
440+++ src/std/dev/devPrintfSoftCallback.c 2012-12-10 21:21:25 +0000
441@@ -0,0 +1,51 @@
442+/*************************************************************************\
443+* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
444+* National Laboratory.
445+* EPICS BASE is distributed subject to a Software License Agreement found
446+* in file LICENSE that is included with this distribution.
447+\*************************************************************************/
448+/* $Revision-Id$ */
449+/*
450+ * Author: Andrew Johnson
451+ * Date: 28 Sept 2012
452+ */
453+
454+#include "alarm.h"
455+#include "dbAccess.h"
456+#include "recGbl.h"
457+#include "printfRecord.h"
458+#include "epicsExport.h"
459+
460+static long write_string(printfRecord *prec)
461+{
462+ struct link *plink = &prec->out;
463+ int dtyp = dbGetLinkDBFtype(plink);
464+ long len = prec->len;
465+ long status;
466+
467+ if (prec->pact || dtyp < 0)
468+ return 0;
469+
470+ if (dtyp != DBR_CHAR && dtyp != DBF_UCHAR) {
471+ dtyp = DBR_STRING;
472+ len = 1;
473+ }
474+
475+ if (plink->type != CA_LINK)
476+ return dbPutLink(plink, dtyp, prec->val, len);
477+
478+ status = dbCaPutLinkCallback(plink, dtyp, prec->val, len,
479+ dbCaCallbackProcess, plink);
480+ if (status) {
481+ recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
482+ return status;
483+ }
484+
485+ prec->pact = TRUE;
486+ return 0;
487+}
488+
489+printfdset devPrintfSoftCallback = {
490+ 5, NULL, NULL, NULL, NULL, write_string
491+};
492+epicsExportAddress(dset, devPrintfSoftCallback);
493
494=== removed file 'src/std/dev/devSoStdio.c'
495--- src/std/dev/devSoStdio.c 2012-07-18 21:45:23 +0000
496+++ src/std/dev/devSoStdio.c 1970-01-01 00:00:00 +0000
497@@ -1,108 +0,0 @@
498-/*************************************************************************\
499-* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
500-* National Laboratory.
501-* EPICS BASE is distributed subject to a Software License Agreement found
502-* in file LICENSE that is included with this distribution.
503-\*************************************************************************/
504-
505-/* $Revision-Id$ */
506-
507-#include <stdio.h>
508-#include <string.h>
509-
510-#include "dbCommon.h"
511-#include "devSup.h"
512-#include "errlog.h"
513-#include "recGbl.h"
514-#include "recSup.h"
515-#include "stringoutRecord.h"
516-#include "epicsExport.h"
517-
518-typedef int (*PRINTFFUNC)(const char *fmt, ...);
519-
520-static int stderrPrintf(const char *fmt, ...);
521-static int logPrintf(const char *fmt, ...);
522-
523-
524-static struct outStream {
525- const char *name;
526- PRINTFFUNC print;
527-} outStreams[] = {
528- {"stdout", printf},
529- {"stderr", stderrPrintf},
530- {"errlog", logPrintf},
531- {NULL, NULL}
532-};
533-
534-static int stderrPrintf(const char *fmt, ...) {
535- va_list pvar;
536- int retval;
537-
538- va_start(pvar, fmt);
539- retval = vfprintf(stderr, fmt, pvar);
540- va_end (pvar);
541-
542- return retval;
543-}
544-
545-static int logPrintf(const char *fmt, ...) {
546- va_list pvar;
547- int retval;
548-
549- va_start(pvar, fmt);
550- retval = errlogVprintf(fmt, pvar);
551- va_end (pvar);
552-
553- return retval;
554-}
555-
556-static long add(dbCommon *pcommon) {
557- stringoutRecord *prec = (stringoutRecord *) pcommon;
558- struct outStream *pstream;
559-
560- if (prec->out.type != INST_IO)
561- return S_dev_badOutType;
562-
563- for (pstream = outStreams; pstream->name; ++pstream) {
564- if (strcmp(prec->out.value.instio.string, pstream->name) == 0) {
565- prec->dpvt = pstream;
566- return 0;
567- }
568- }
569- prec->dpvt = NULL;
570- return -1;
571-}
572-
573-static long del(dbCommon *pcommon) {
574- stringoutRecord *prec = (stringoutRecord *) pcommon;
575-
576- prec->dpvt = NULL;
577- return 0;
578-}
579-
580-static struct dsxt dsxtSoStdio = {
581- add, del
582-};
583-
584-static long init(int pass)
585-{
586- if (pass == 0) devExtend(&dsxtSoStdio);
587- return 0;
588-}
589-
590-static long write_string(stringoutRecord *prec)
591-{
592- struct outStream *pstream = (struct outStream *)prec->dpvt;
593- if (pstream)
594- pstream->print("%s\n", prec->val);
595- return 0;
596-}
597-
598-/* Create the dset for devSoStdio */
599-static struct {
600- dset common;
601- DEVSUPFUN write;
602-} devSoStdio = {
603- {5, NULL, init, NULL, NULL}, write_string
604-};
605-epicsExportAddress(dset, devSoStdio);
606
607=== modified file 'src/std/dev/devSoft.dbd'
608--- src/std/dev/devSoft.dbd 2012-07-11 23:07:23 +0000
609+++ src/std/dev/devSoft.dbd 2012-12-10 21:21:25 +0000
610@@ -9,10 +9,13 @@
611 device(histogram,CONSTANT,devHistogramSoft,"Soft Channel")
612 device(longin,CONSTANT,devLiSoft,"Soft Channel")
613 device(longout,CONSTANT,devLoSoft,"Soft Channel")
614+device(lsi,CONSTANT,devLsiSoft,"Soft Channel")
615+device(lso,CONSTANT,devLsoSoft,"Soft Channel")
616 device(mbbi,CONSTANT,devMbbiSoft,"Soft Channel")
617 device(mbbiDirect,CONSTANT,devMbbiDirectSoft,"Soft Channel")
618 device(mbbo,CONSTANT,devMbboSoft,"Soft Channel")
619 device(mbboDirect,CONSTANT,devMbboDirectSoft,"Soft Channel")
620+device(printf,CONSTANT,devPrintfSoft,"Soft Channel")
621 device(stringin,CONSTANT,devSiSoft,"Soft Channel")
622 device(stringout,CONSTANT,devSoSoft,"Soft Channel")
623 device(subArray,CONSTANT,devSASoft,"Soft Channel")
624@@ -34,10 +37,12 @@
625 device(calcout,CONSTANT,devCalcoutSoftCallback,"Async Soft Channel")
626 device(longin,CONSTANT,devLiSoftCallback,"Async Soft Channel")
627 device(longout,CONSTANT,devLoSoftCallback,"Async Soft Channel")
628+device(lso,CONSTANT,devLsoSoftCallback,"Async Soft Channel")
629 device(mbbi,CONSTANT,devMbbiSoftCallback,"Async Soft Channel")
630 device(mbbiDirect,CONSTANT,devMbbiDirectSoftCallback,"Async Soft Channel")
631 device(mbbo,CONSTANT,devMbboSoftCallback,"Async Soft Channel")
632 device(mbboDirect,CONSTANT,devMbboDirectSoftCallback,"Async Soft Channel")
633+device(printf,CONSTANT,devPrintfSoftCallback,"Async Soft Channel")
634 device(stringin,CONSTANT,devSiSoftCallback,"Async Soft Channel")
635 device(stringout,CONSTANT,devSoSoftCallback,"Async Soft Channel")
636
637@@ -49,6 +54,8 @@
638 device(longin, INST_IO,devLiGeneralTime,"General Time")
639 device(stringin,INST_IO,devSiGeneralTime,"General Time")
640
641+device(lso,INST_IO,devLsoStdio,"stdio")
642+device(printf,INST_IO,devPrintfStdio,"stdio")
643 device(stringout,INST_IO,devSoStdio,"stdio")
644
645 device(bi, INST_IO, devBiDbState, "Db State")
646
647=== added file 'src/std/dev/devStdio.c'
648--- src/std/dev/devStdio.c 1970-01-01 00:00:00 +0000
649+++ src/std/dev/devStdio.c 2012-12-10 21:21:25 +0000
650@@ -0,0 +1,212 @@
651+/*************************************************************************\
652+* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
653+* National Laboratory.
654+* EPICS BASE is distributed subject to a Software License Agreement found
655+* in file LICENSE that is included with this distribution.
656+\*************************************************************************/
657+
658+/* $Revision-Id$ */
659+
660+#include <stdio.h>
661+#include <string.h>
662+
663+#include "dbCommon.h"
664+#include "devSup.h"
665+#include "errlog.h"
666+#include "recGbl.h"
667+#include "recSup.h"
668+#include "lsoRecord.h"
669+#include "printfRecord.h"
670+#include "stringoutRecord.h"
671+#include "epicsExport.h"
672+
673+typedef int (*PRINTFFUNC)(const char *fmt, ...);
674+
675+static int stderrPrintf(const char *fmt, ...);
676+static int logPrintf(const char *fmt, ...);
677+
678+
679+static struct outStream {
680+ const char *name;
681+ PRINTFFUNC print;
682+} outStreams[] = {
683+ {"stdout", printf},
684+ {"stderr", stderrPrintf},
685+ {"errlog", logPrintf},
686+ {NULL, NULL}
687+};
688+
689+static int stderrPrintf(const char *fmt, ...) {
690+ va_list pvar;
691+ int retval;
692+
693+ va_start(pvar, fmt);
694+ retval = vfprintf(stderr, fmt, pvar);
695+ va_end (pvar);
696+
697+ return retval;
698+}
699+
700+static int logPrintf(const char *fmt, ...) {
701+ va_list pvar;
702+ int retval;
703+
704+ va_start(pvar, fmt);
705+ retval = errlogVprintf(fmt, pvar);
706+ va_end (pvar);
707+
708+ return retval;
709+}
710+
711+
712+/* lso device support */
713+
714+static long add_lso(dbCommon *pcommon) {
715+ lsoRecord *prec = (lsoRecord *) pcommon;
716+ struct outStream *pstream;
717+
718+ if (prec->out.type != INST_IO)
719+ return S_dev_badOutType;
720+
721+ for (pstream = outStreams; pstream->name; ++pstream) {
722+ if (strcmp(prec->out.value.instio.string, pstream->name) == 0) {
723+ prec->dpvt = pstream;
724+ return 0;
725+ }
726+ }
727+ prec->dpvt = NULL;
728+ return -1;
729+}
730+
731+static long del_lso(dbCommon *pcommon) {
732+ lsoRecord *prec = (lsoRecord *) pcommon;
733+
734+ prec->dpvt = NULL;
735+ return 0;
736+}
737+
738+static struct dsxt dsxtLsoStdio = {
739+ add_lso, del_lso
740+};
741+
742+static long init_lso(int pass)
743+{
744+ if (pass == 0) devExtend(&dsxtLsoStdio);
745+ return 0;
746+}
747+
748+static long write_lso(lsoRecord *prec)
749+{
750+ struct outStream *pstream = (struct outStream *)prec->dpvt;
751+ if (pstream)
752+ pstream->print("%s\n", prec->val);
753+ return 0;
754+}
755+
756+lsodset devLsoStdio = {
757+ 5, NULL, init_lso, NULL, NULL, write_lso
758+};
759+epicsExportAddress(dset, devLsoStdio);
760+
761+
762+/* printf device support */
763+
764+static long add_printf(dbCommon *pcommon) {
765+ printfRecord *prec = (printfRecord *) pcommon;
766+ struct outStream *pstream;
767+
768+ if (prec->out.type != INST_IO)
769+ return S_dev_badOutType;
770+
771+ for (pstream = outStreams; pstream->name; ++pstream) {
772+ if (strcmp(prec->out.value.instio.string, pstream->name) == 0) {
773+ prec->dpvt = pstream;
774+ return 0;
775+ }
776+ }
777+ prec->dpvt = NULL;
778+ return -1;
779+}
780+
781+static long del_printf(dbCommon *pcommon) {
782+ printfRecord *prec = (printfRecord *) pcommon;
783+
784+ prec->dpvt = NULL;
785+ return 0;
786+}
787+
788+static struct dsxt dsxtPrintfStdio = {
789+ add_printf, del_printf
790+};
791+
792+static long init_printf(int pass)
793+{
794+ if (pass == 0) devExtend(&dsxtPrintfStdio);
795+ return 0;
796+}
797+
798+static long write_printf(printfRecord *prec)
799+{
800+ struct outStream *pstream = (struct outStream *)prec->dpvt;
801+ if (pstream)
802+ pstream->print("%s\n", prec->val);
803+ return 0;
804+}
805+
806+printfdset devPrintfStdio = {
807+ 5, NULL, init_printf, NULL, NULL, write_printf
808+};
809+epicsExportAddress(dset, devPrintfStdio);
810+
811+
812+/* stringout device support */
813+
814+static long add_stringout(dbCommon *pcommon) {
815+ stringoutRecord *prec = (stringoutRecord *) pcommon;
816+ struct outStream *pstream;
817+
818+ if (prec->out.type != INST_IO)
819+ return S_dev_badOutType;
820+
821+ for (pstream = outStreams; pstream->name; ++pstream) {
822+ if (strcmp(prec->out.value.instio.string, pstream->name) == 0) {
823+ prec->dpvt = pstream;
824+ return 0;
825+ }
826+ }
827+ prec->dpvt = NULL;
828+ return -1;
829+}
830+
831+static long del_stringout(dbCommon *pcommon) {
832+ stringoutRecord *prec = (stringoutRecord *) pcommon;
833+
834+ prec->dpvt = NULL;
835+ return 0;
836+}
837+
838+static struct dsxt dsxtSoStdio = {
839+ add_stringout, del_stringout
840+};
841+
842+static long init_stringout(int pass)
843+{
844+ if (pass == 0) devExtend(&dsxtSoStdio);
845+ return 0;
846+}
847+
848+static long write_stringout(stringoutRecord *prec)
849+{
850+ struct outStream *pstream = (struct outStream *)prec->dpvt;
851+ if (pstream)
852+ pstream->print("%s\n", prec->val);
853+ return 0;
854+}
855+
856+static struct {
857+ dset common;
858+ DEVSUPFUN write;
859+} devSoStdio = {
860+ {5, NULL, init_stringout, NULL, NULL}, write_stringout
861+};
862+epicsExportAddress(dset, devSoStdio);
863
864=== modified file 'src/std/rec/Makefile'
865--- src/std/rec/Makefile 2011-11-14 23:42:50 +0000
866+++ src/std/rec/Makefile 2012-12-10 21:21:25 +0000
867@@ -11,67 +11,43 @@
868
869 SRC_DIRS += $(STDDIR)/rec
870
871-DBDINC += aaiRecord
872-DBDINC += aaoRecord
873-DBDINC += aiRecord
874-DBDINC += aoRecord
875-DBDINC += aSubRecord
876-DBDINC += biRecord
877-DBDINC += boRecord
878-DBDINC += calcRecord
879-DBDINC += calcoutRecord
880-DBDINC += compressRecord
881-DBDINC += dfanoutRecord
882-DBDINC += eventRecord
883-DBDINC += fanoutRecord
884-DBDINC += histogramRecord
885-DBDINC += longinRecord
886-DBDINC += longoutRecord
887-DBDINC += mbbiRecord
888-DBDINC += mbbiDirectRecord
889-DBDINC += mbboRecord
890-DBDINC += mbboDirectRecord
891-DBDINC += permissiveRecord
892-DBDINC += selRecord
893-DBDINC += seqRecord
894-DBDINC += stateRecord
895-DBDINC += stringinRecord
896-DBDINC += stringoutRecord
897-DBDINC += subRecord
898-DBDINC += subArrayRecord
899-DBDINC += waveformRecord
900+stdRecords += aaiRecord
901+stdRecords += aaoRecord
902+stdRecords += aiRecord
903+stdRecords += aoRecord
904+stdRecords += aSubRecord
905+stdRecords += biRecord
906+stdRecords += boRecord
907+stdRecords += calcRecord
908+stdRecords += calcoutRecord
909+stdRecords += compressRecord
910+stdRecords += dfanoutRecord
911+stdRecords += eventRecord
912+stdRecords += fanoutRecord
913+stdRecords += histogramRecord
914+stdRecords += longinRecord
915+stdRecords += longoutRecord
916+stdRecords += lsiRecord
917+stdRecords += lsoRecord
918+stdRecords += mbbiRecord
919+stdRecords += mbbiDirectRecord
920+stdRecords += mbboRecord
921+stdRecords += mbboDirectRecord
922+stdRecords += permissiveRecord
923+stdRecords += printfRecord
924+stdRecords += selRecord
925+stdRecords += seqRecord
926+stdRecords += stateRecord
927+stdRecords += stringinRecord
928+stdRecords += stringoutRecord
929+stdRecords += subRecord
930+stdRecords += subArrayRecord
931+stdRecords += waveformRecord
932
933+DBDINC += $(stdRecords)
934 DBD += stdRecords.dbd
935
936-stdRecords_DBD = $(patsubst %,%.dbd,$(DBDINC))
937+stdRecords_DBD = $(patsubst %,%.dbd,$(stdRecords))
938
939-dbRecStd_SRCS += aaiRecord.c
940-dbRecStd_SRCS += aaoRecord.c
941-dbRecStd_SRCS += aiRecord.c
942-dbRecStd_SRCS += aoRecord.c
943-dbRecStd_SRCS += aSubRecord.c
944-dbRecStd_SRCS += biRecord.c
945-dbRecStd_SRCS += boRecord.c
946-dbRecStd_SRCS += calcRecord.c
947-dbRecStd_SRCS += calcoutRecord.c
948-dbRecStd_SRCS += compressRecord.c
949-dbRecStd_SRCS += dfanoutRecord.c
950-dbRecStd_SRCS += eventRecord.c
951-dbRecStd_SRCS += fanoutRecord.c
952-dbRecStd_SRCS += histogramRecord.c
953-dbRecStd_SRCS += longinRecord.c
954-dbRecStd_SRCS += longoutRecord.c
955-dbRecStd_SRCS += mbbiRecord.c
956-dbRecStd_SRCS += mbbiDirectRecord.c
957-dbRecStd_SRCS += mbboRecord.c
958-dbRecStd_SRCS += mbboDirectRecord.c
959-dbRecStd_SRCS += permissiveRecord.c
960-dbRecStd_SRCS += selRecord.c
961-dbRecStd_SRCS += seqRecord.c
962-dbRecStd_SRCS += stateRecord.c
963-dbRecStd_SRCS += stringinRecord.c
964-dbRecStd_SRCS += stringoutRecord.c
965-dbRecStd_SRCS += subRecord.c
966-dbRecStd_SRCS += subArrayRecord.c
967-dbRecStd_SRCS += waveformRecord.c
968+dbRecStd_SRCS += $(patsubst %,%.c,$(stdRecords))
969
970
971=== modified file 'src/std/rec/RULES'
972--- src/std/rec/RULES 2011-02-27 00:24:51 +0000
973+++ src/std/rec/RULES 2012-12-10 21:21:25 +0000
974@@ -9,7 +9,7 @@
975
976 # This is a Makefile fragment, see src/std/Makefile.
977
978-$(COMMON_DIR)/stdRecords.dbd:
979+$(COMMON_DIR)/stdRecords.dbd: ../rec/Makefile
980 $(RM) $@
981 $(PERL) $(TOOLS)/makeIncludeDbd.pl $(stdRecords_DBD) $@
982
983
984=== added file 'src/std/rec/lsiRecord.c'
985--- src/std/rec/lsiRecord.c 1970-01-01 00:00:00 +0000
986+++ src/std/rec/lsiRecord.c 2012-12-10 21:21:25 +0000
987@@ -0,0 +1,284 @@
988+/*************************************************************************\
989+* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
990+* National Laboratory.
991+* EPICS BASE is distributed subject to a Software License Agreement found
992+* in file LICENSE that is included with this distribution.
993+\*************************************************************************/
994+
995+/* Long String Input record type */
996+/*
997+ * Author: Andrew Johnson
998+ * Date: 2012-11-27
999+ */
1000+
1001+#include <stddef.h>
1002+#include <stdio.h>
1003+#include <string.h>
1004+
1005+#include "dbDefs.h"
1006+#include "errlog.h"
1007+#include "alarm.h"
1008+#include "cantProceed.h"
1009+#include "dbAccess.h"
1010+#include "dbEvent.h"
1011+#include "dbFldTypes.h"
1012+#include "errMdef.h"
1013+#include "menuPost.h"
1014+#include "menuYesNo.h"
1015+#include "recSup.h"
1016+#include "recGbl.h"
1017+#include "special.h"
1018+#define GEN_SIZE_OFFSET
1019+#include "lsiRecord.h"
1020+#undef GEN_SIZE_OFFSET
1021+#include "epicsExport.h"
1022+
1023+static void monitor(lsiRecord *);
1024+static long readValue(lsiRecord *);
1025+
1026+static long init_record(lsiRecord *prec, int pass)
1027+{
1028+ lsidset *pdset;
1029+
1030+ if (pass == 0) {
1031+ size_t sizv = prec->sizv;
1032+
1033+ if (sizv < 16) {
1034+ sizv = 16; /* Enforce a minimum size for the VAL field */
1035+ prec->sizv = sizv;
1036+ }
1037+
1038+ prec->val = callocMustSucceed(1, sizv, "lsi::init_record");
1039+ prec->len = 0;
1040+ prec->oval = callocMustSucceed(1, sizv, "lsi::init_record");
1041+ prec->olen = 0;
1042+ return 0;
1043+ }
1044+
1045+ dbLoadLink(&prec->siml, DBF_USHORT, &prec->simm);
1046+
1047+ pdset = (lsidset *) prec->dset;
1048+ if (!pdset) {
1049+ recGblRecordError(S_dev_noDSET, prec, "lsi: init_record");
1050+ return S_dev_noDSET;
1051+ }
1052+
1053+ /* must have a read_string function */
1054+ if (pdset->number < 5 || !pdset->read_string) {
1055+ recGblRecordError(S_dev_missingSup, prec, "lsi: init_record");
1056+ return S_dev_missingSup;
1057+ }
1058+
1059+ if (pdset->init_record) {
1060+ long status = pdset->init_record(prec);
1061+
1062+ if (status)
1063+ return status;
1064+ }
1065+
1066+ if (prec->len) {
1067+ strcpy(prec->oval, prec->val);
1068+ prec->olen = prec->len;
1069+ prec->udf = FALSE;
1070+ }
1071+
1072+ return 0;
1073+}
1074+
1075+static long process(lsiRecord *prec)
1076+{
1077+ int pact = prec->pact;
1078+ lsidset *pdset = (lsidset *) prec->dset;
1079+ long status = 0;
1080+
1081+ if (!pdset || !pdset->read_string) {
1082+ prec->pact = TRUE;
1083+ recGblRecordError(S_dev_missingSup, prec, "lsi: read_string");
1084+ return S_dev_missingSup;
1085+ }
1086+
1087+ status = readValue(prec); /* read the new value */
1088+ if (!pact && prec->pact)
1089+ return 0;
1090+
1091+ prec->pact = TRUE;
1092+ recGblGetTimeStamp(prec);
1093+
1094+ monitor(prec);
1095+
1096+ /* Wrap up */
1097+ recGblFwdLink(prec);
1098+ prec->pact = FALSE;
1099+ return status;
1100+}
1101+
1102+static long cvt_dbaddr(DBADDR *paddr)
1103+{
1104+ lsiRecord *prec = (lsiRecord *) paddr->precord;
1105+ int fieldIndex = dbGetFieldIndex(paddr);
1106+
1107+ if (fieldIndex == lsiRecordVAL) {
1108+ paddr->pfield = prec->val;
1109+ paddr->special = SPC_MOD;
1110+ }
1111+ else if (fieldIndex == lsiRecordOVAL) {
1112+ paddr->pfield = prec->oval;
1113+ paddr->special = SPC_NOMOD;
1114+ }
1115+ else {
1116+ errlogPrintf("lsiRecord::cvt_dbaddr called for %s.%s\n",
1117+ prec->name, paddr->pfldDes->name);
1118+ return -1;
1119+ }
1120+
1121+ paddr->no_elements = 1;
1122+ paddr->field_type = DBF_STRING;
1123+ paddr->dbr_field_type = DBF_STRING;
1124+ paddr->field_size = prec->sizv;
1125+ return 0;
1126+}
1127+
1128+static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
1129+{
1130+ lsiRecord *prec = (lsiRecord *) paddr->precord;
1131+ int fieldIndex = dbGetFieldIndex(paddr);
1132+
1133+ if (fieldIndex == lsiRecordVAL)
1134+ *no_elements = prec->len;
1135+ else if (fieldIndex == lsiRecordOVAL)
1136+ *no_elements = prec->olen;
1137+ else
1138+ return -1;
1139+
1140+ *offset = 0;
1141+ return 0;
1142+}
1143+
1144+static long put_array_info(DBADDR *paddr, long nNew)
1145+{
1146+ lsiRecord *prec = (lsiRecord *) paddr->precord;
1147+
1148+ if (nNew == prec->sizv)
1149+ --nNew; /* truncated string */
1150+ prec->val[nNew] = 0; /* ensure data is terminated */
1151+
1152+ return 0;
1153+}
1154+
1155+static long special(DBADDR *paddr, int after)
1156+{
1157+ lsiRecord *prec = (lsiRecord *) paddr->precord;
1158+
1159+ if (!after)
1160+ return 0;
1161+
1162+ /* We set prec->len here and not in put_array_info()
1163+ * because that does not get called if the put was
1164+ * done using a DBR_STRING type.
1165+ */
1166+ prec->len = strlen(prec->val) + 1;
1167+ db_post_events(prec, &prec->len, DBE_VALUE | DBE_LOG);
1168+
1169+ return 0;
1170+}
1171+
1172+static void monitor(lsiRecord *prec)
1173+{
1174+ epicsUInt16 events = recGblResetAlarms(prec);
1175+
1176+ if (prec->len != prec->olen ||
1177+ memcmp(prec->oval, prec->val, prec->len)) {
1178+ events |= DBE_VALUE | DBE_LOG;
1179+ memcpy(prec->oval, prec->val, prec->len);
1180+ }
1181+
1182+ if (prec->len != prec->olen) {
1183+ prec->olen = prec->len;
1184+ db_post_events(prec, &prec->len, DBE_VALUE | DBE_LOG);
1185+ }
1186+
1187+ if (prec->mpst == menuPost_Always)
1188+ events |= DBE_VALUE;
1189+ if (prec->apst == menuPost_Always)
1190+ events |= DBE_LOG;
1191+
1192+ if (events)
1193+ db_post_events(prec, prec->val, events);
1194+}
1195+
1196+static long readValue(lsiRecord *prec)
1197+{
1198+ long status;
1199+ lsidset *pdset = (lsidset *) prec->dset;
1200+
1201+ if (prec->pact)
1202+ goto read;
1203+
1204+ status = dbGetLink(&prec->siml, DBR_USHORT, &prec->simm, 0, 0);
1205+ if (status)
1206+ return status;
1207+
1208+ switch (prec->simm) {
1209+ case menuYesNoNO:
1210+read:
1211+ status = pdset->read_string(prec);
1212+ break;
1213+
1214+ case menuYesNoYES:
1215+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
1216+ status = dbGetLinkLS(&prec->siol, prec->val, prec->sizv, &prec->len);
1217+ break;
1218+
1219+ default:
1220+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
1221+ status = -1;
1222+ }
1223+
1224+ if (!status)
1225+ prec->udf = FALSE;
1226+
1227+ return status;
1228+}
1229+
1230+
1231+/* Create Record Support Entry Table*/
1232+
1233+#define report NULL
1234+#define initialize NULL
1235+/* init_record */
1236+/* process */
1237+/* special */
1238+#define get_value NULL
1239+/* cvt_dbaddr */
1240+/* get_array_info */
1241+/* put_array_info */
1242+#define get_units NULL
1243+#define get_precision NULL
1244+#define get_enum_str NULL
1245+#define get_enum_strs NULL
1246+#define put_enum_str NULL
1247+#define get_graphic_double NULL
1248+#define get_control_double NULL
1249+#define get_alarm_double NULL
1250+
1251+rset lsiRSET = {
1252+ RSETNUMBER,
1253+ report,
1254+ initialize,
1255+ init_record,
1256+ process,
1257+ special,
1258+ get_value,
1259+ cvt_dbaddr,
1260+ get_array_info,
1261+ put_array_info,
1262+ get_units,
1263+ get_precision,
1264+ get_enum_str,
1265+ get_enum_strs,
1266+ put_enum_str,
1267+ get_graphic_double,
1268+ get_control_double,
1269+ get_alarm_double
1270+};
1271+epicsExportAddress(rset, lsiRSET);
1272
1273=== added file 'src/std/rec/lsiRecord.dbd'
1274--- src/std/rec/lsiRecord.dbd 1970-01-01 00:00:00 +0000
1275+++ src/std/rec/lsiRecord.dbd 2012-12-10 21:21:25 +0000
1276@@ -0,0 +1,88 @@
1277+#*************************************************************************
1278+# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
1279+# National Laboratory.
1280+# EPICS BASE is distributed subject to a Software License Agreement found
1281+# in file LICENSE that is included with this distribution.
1282+#*************************************************************************
1283+
1284+recordtype(lsi) {
1285+ include "dbCommon.dbd"
1286+ %#include "devSup.h"
1287+ %
1288+ %/* Declare Device Support Entry Table */
1289+ %typedef struct lsidset {
1290+ % long number;
1291+ % DEVSUPFUN report;
1292+ % DEVSUPFUN init;
1293+ % DEVSUPFUN init_record;
1294+ % DEVSUPFUN get_ioint_info;
1295+ % DEVSUPFUN read_string;
1296+ %} lsidset;
1297+ %
1298+ field(VAL,DBF_NOACCESS) {
1299+ prompt("Current Value")
1300+ asl(ASL0)
1301+ pp(TRUE)
1302+ special(SPC_DBADDR)
1303+ extra("char *val")
1304+ }
1305+ field(OVAL,DBF_NOACCESS) {
1306+ prompt("Old Value")
1307+ special(SPC_DBADDR)
1308+ interest(3)
1309+ extra("char *oval")
1310+ }
1311+ field(SIZV,DBF_USHORT) {
1312+ prompt("Size of buffers")
1313+ promptgroup(GUI_OUTPUT)
1314+ special(SPC_NOMOD)
1315+ interest(1)
1316+ initial("41")
1317+ }
1318+ field(LEN,DBF_ULONG) {
1319+ prompt("Length of VAL")
1320+ special(SPC_NOMOD)
1321+ }
1322+ field(OLEN,DBF_ULONG) {
1323+ prompt("Length of OVAL")
1324+ special(SPC_NOMOD)
1325+ }
1326+ field(INP,DBF_INLINK) {
1327+ prompt("Input Specification")
1328+ promptgroup(GUI_INPUTS)
1329+ interest(1)
1330+ }
1331+ field(MPST,DBF_MENU) {
1332+ prompt("Post Value Monitors")
1333+ promptgroup(GUI_DISPLAY)
1334+ interest(1)
1335+ menu(menuPost)
1336+ }
1337+ field(APST,DBF_MENU) {
1338+ prompt("Post Archive Monitors")
1339+ promptgroup(GUI_DISPLAY)
1340+ interest(1)
1341+ menu(menuPost)
1342+ }
1343+ field(SIML,DBF_INLINK) {
1344+ prompt("Simulation Mode Link")
1345+ promptgroup(GUI_INPUTS)
1346+ interest(2)
1347+ }
1348+ field(SIMM,DBF_MENU) {
1349+ prompt("Simulation Mode")
1350+ interest(2)
1351+ menu(menuYesNo)
1352+ }
1353+ field(SIMS,DBF_MENU) {
1354+ prompt("Simulation Mode Severity")
1355+ promptgroup(GUI_INPUTS)
1356+ interest(2)
1357+ menu(menuAlarmSevr)
1358+ }
1359+ field(SIOL,DBF_INLINK) {
1360+ prompt("Sim Input Specifctn")
1361+ promptgroup(GUI_INPUTS)
1362+ interest(2)
1363+ }
1364+}
1365
1366=== added file 'src/std/rec/lsoRecord.c'
1367--- src/std/rec/lsoRecord.c 1970-01-01 00:00:00 +0000
1368+++ src/std/rec/lsoRecord.c 2012-12-10 21:21:25 +0000
1369@@ -0,0 +1,322 @@
1370+/*************************************************************************\
1371+* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
1372+* National Laboratory.
1373+* EPICS BASE is distributed subject to a Software License Agreement found
1374+* in file LICENSE that is included with this distribution.
1375+\*************************************************************************/
1376+
1377+/* Long String Output record type */
1378+/*
1379+ * Author: Andrew Johnson
1380+ * Date: 2012-11-28
1381+ */
1382+
1383+
1384+#include <stddef.h>
1385+#include <stdio.h>
1386+#include <string.h>
1387+
1388+#include "dbDefs.h"
1389+#include "errlog.h"
1390+#include "alarm.h"
1391+#include "cantProceed.h"
1392+#include "dbAccess.h"
1393+#include "dbEvent.h"
1394+#include "dbFldTypes.h"
1395+#include "devSup.h"
1396+#include "errMdef.h"
1397+#include "menuIvoa.h"
1398+#include "menuOmsl.h"
1399+#include "menuPost.h"
1400+#include "menuYesNo.h"
1401+#include "recSup.h"
1402+#include "recGbl.h"
1403+#include "special.h"
1404+#define GEN_SIZE_OFFSET
1405+#include "lsoRecord.h"
1406+#undef GEN_SIZE_OFFSET
1407+#include "epicsExport.h"
1408+
1409+static void monitor(lsoRecord *);
1410+static long writeValue(lsoRecord *);
1411+
1412+static long init_record(lsoRecord *prec, int pass)
1413+{
1414+ lsodset *pdset;
1415+
1416+ if (pass == 0) {
1417+ size_t sizv = prec->sizv;
1418+
1419+ if (sizv < 16) {
1420+ sizv = 16; /* Enforce a minimum size for the VAL field */
1421+ prec->sizv = sizv;
1422+ }
1423+
1424+ prec->val = callocMustSucceed(1, sizv, "lso::init_record");
1425+ prec->len = 0;
1426+ prec->oval = callocMustSucceed(1, sizv, "lso::init_record");
1427+ prec->olen = 0;
1428+ return 0;
1429+ }
1430+
1431+ dbLoadLink(&prec->siml, DBF_USHORT, &prec->simm);
1432+
1433+ pdset = (lsodset *) prec->dset;
1434+ if (!pdset) {
1435+ recGblRecordError(S_dev_noDSET, prec, "lso: init_record");
1436+ return S_dev_noDSET;
1437+ }
1438+
1439+ /* must have a write_string function defined */
1440+ if (pdset->number < 5 || !pdset->write_string) {
1441+ recGblRecordError(S_dev_missingSup, prec, "lso: init_record");
1442+ return S_dev_missingSup;
1443+ }
1444+
1445+ dbLoadLinkLS(&prec->dol, prec->val, prec->sizv, &prec->len);
1446+
1447+ if (pdset->init_record) {
1448+ long status = pdset->init_record(prec);
1449+
1450+ if (status)
1451+ return status;
1452+ }
1453+
1454+ if (prec->len) {
1455+ strcpy(prec->oval, prec->val);
1456+ prec->olen = prec->len;
1457+ prec->udf = FALSE;
1458+ }
1459+
1460+ return 0;
1461+}
1462+
1463+static long process(lsoRecord *prec)
1464+{
1465+ int pact = prec->pact;
1466+ lsodset *pdset = (lsodset *) prec->dset;
1467+ long status = 0;
1468+
1469+ if (!pdset || !pdset->write_string) {
1470+ prec->pact = TRUE;
1471+ recGblRecordError(S_dev_missingSup, prec, "lso: write_string");
1472+ return S_dev_missingSup;
1473+ }
1474+
1475+ if (!pact && prec->omsl == menuOmslclosed_loop)
1476+ if (!dbGetLinkLS(&prec->dol, prec->val, prec->sizv, &prec->len))
1477+ prec->udf = FALSE;
1478+
1479+ if (prec->udf)
1480+ recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM);
1481+
1482+ if (prec->nsev < INVALID_ALARM )
1483+ status = writeValue(prec); /* write the new value */
1484+ else {
1485+ switch (prec->ivoa) {
1486+ case menuIvoaContinue_normally:
1487+ status = writeValue(prec); /* write the new value */
1488+ break;
1489+
1490+ case menuIvoaDon_t_drive_outputs:
1491+ break;
1492+
1493+ case menuIvoaSet_output_to_IVOV:
1494+ if (!prec->pact) {
1495+ size_t size = prec->sizv - 1;
1496+
1497+ strncpy(prec->val, prec->ivov, size);
1498+ prec->val[size] = 0;
1499+ prec->len = strlen(prec->val) + 1;
1500+ }
1501+ status = writeValue(prec); /* write the new value */
1502+ break;
1503+
1504+ default:
1505+ status = -1;
1506+ recGblRecordError(S_db_badField, prec,
1507+ "lso:process Bad IVOA choice");
1508+ }
1509+ }
1510+
1511+ /* Asynchronous if device support set pact */
1512+ if (!pact && prec->pact)
1513+ return status;
1514+
1515+ prec->pact = TRUE;
1516+ recGblGetTimeStamp(prec);
1517+
1518+ monitor(prec);
1519+
1520+ /* Wrap up */
1521+ recGblFwdLink(prec);
1522+ prec->pact = FALSE;
1523+ return status;
1524+}
1525+
1526+static long cvt_dbaddr(DBADDR *paddr)
1527+{
1528+ lsoRecord *prec = (lsoRecord *) paddr->precord;
1529+ int fieldIndex = dbGetFieldIndex(paddr);
1530+
1531+ if (fieldIndex == lsoRecordVAL) {
1532+ paddr->pfield = prec->val;
1533+ paddr->special = SPC_MOD;
1534+ }
1535+ else if (fieldIndex == lsoRecordOVAL) {
1536+ paddr->pfield = prec->oval;
1537+ paddr->special = SPC_NOMOD;
1538+ }
1539+ else {
1540+ errlogPrintf("lsoRecord::cvt_dbaddr called for %s.%s\n",
1541+ prec->name, paddr->pfldDes->name);
1542+ return -1;
1543+ }
1544+
1545+ paddr->no_elements = 1;
1546+ paddr->field_type = DBF_STRING;
1547+ paddr->dbr_field_type = DBF_STRING;
1548+ paddr->field_size = prec->sizv;
1549+ return 0;
1550+}
1551+
1552+static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
1553+{
1554+ lsoRecord *prec = (lsoRecord *) paddr->precord;
1555+ int fieldIndex = dbGetFieldIndex(paddr);
1556+
1557+ if (fieldIndex == lsoRecordVAL)
1558+ *no_elements = prec->len;
1559+ else if (fieldIndex == lsoRecordOVAL)
1560+ *no_elements = prec->olen;
1561+ else
1562+ return -1;
1563+
1564+ *offset = 0;
1565+ return 0;
1566+}
1567+
1568+static long put_array_info(DBADDR *paddr, long nNew)
1569+{
1570+ lsoRecord *prec = (lsoRecord *) paddr->precord;
1571+
1572+ if (nNew == prec->sizv)
1573+ --nNew; /* truncated string */
1574+ prec->val[nNew] = 0; /* ensure data is terminated */
1575+
1576+ return 0;
1577+}
1578+
1579+static long special(DBADDR *paddr, int after)
1580+{
1581+ lsoRecord *prec = (lsoRecord *) paddr->precord;
1582+
1583+ if (!after)
1584+ return 0;
1585+
1586+ /* We set prec->len here and not in put_array_info()
1587+ * because that does not get called if the put was
1588+ * done using a DBR_STRING type.
1589+ */
1590+ prec->len = strlen(prec->val) + 1;
1591+ db_post_events(prec, &prec->len, DBE_VALUE | DBE_LOG);
1592+
1593+ return 0;
1594+}
1595+
1596+static void monitor(lsoRecord *prec)
1597+{
1598+ epicsUInt16 events = recGblResetAlarms(prec);
1599+
1600+ if (prec->len != prec->olen ||
1601+ memcmp(prec->oval, prec->val, prec->len)) {
1602+ events |= DBE_VALUE | DBE_LOG;
1603+ memcpy(prec->oval, prec->val, prec->len);
1604+ }
1605+
1606+ if (prec->len != prec->olen) {
1607+ prec->olen = prec->len;
1608+ db_post_events(prec, &prec->len, DBE_VALUE | DBE_LOG);
1609+ }
1610+
1611+ if (prec->mpst == menuPost_Always)
1612+ events |= DBE_VALUE;
1613+ if (prec->apst == menuPost_Always)
1614+ events |= DBE_LOG;
1615+
1616+ if (events)
1617+ db_post_events(prec, prec->val, events);
1618+}
1619+
1620+static long writeValue(lsoRecord *prec)
1621+{
1622+ long status;
1623+ lsodset *pdset = (lsodset *) prec->dset;
1624+
1625+ if (prec->pact)
1626+ goto write;
1627+
1628+ status = dbGetLink(&prec->siml, DBR_USHORT, &prec->simm, 0, 0);
1629+ if (status)
1630+ return(status);
1631+
1632+ switch (prec->simm) {
1633+ case menuYesNoNO:
1634+write:
1635+ status = pdset->write_string(prec);
1636+ break;
1637+
1638+ case menuYesNoYES:
1639+ recGblSetSevr(prec, SIMM_ALARM, prec->sims);
1640+ status = dbPutLink(&prec->siol,DBR_STRING, prec->val,1);
1641+ break;
1642+
1643+ default:
1644+ recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
1645+ status = -1;
1646+ }
1647+
1648+ return status;
1649+}
1650+
1651+/* Create Record Support Entry Table*/
1652+
1653+#define report NULL
1654+#define initialize NULL
1655+/* init_record */
1656+/* process */
1657+/* special */
1658+#define get_value NULL
1659+/* cvt_dbaddr */
1660+/* get_array_info */
1661+/* put_array_info */
1662+#define get_units NULL
1663+#define get_precision NULL
1664+#define get_enum_str NULL
1665+#define get_enum_strs NULL
1666+#define put_enum_str NULL
1667+#define get_graphic_double NULL
1668+#define get_control_double NULL
1669+#define get_alarm_double NULL
1670+
1671+rset lsoRSET = {
1672+ RSETNUMBER,
1673+ report,
1674+ initialize,
1675+ init_record,
1676+ process,
1677+ special,
1678+ get_value,
1679+ cvt_dbaddr,
1680+ get_array_info,
1681+ put_array_info,
1682+ get_units,
1683+ get_precision,
1684+ get_enum_str,
1685+ get_enum_strs,
1686+ put_enum_str,
1687+ get_graphic_double,
1688+ get_control_double,
1689+ get_alarm_double
1690+};
1691+epicsExportAddress(rset, lsoRSET);
1692
1693=== added file 'src/std/rec/lsoRecord.dbd'
1694--- src/std/rec/lsoRecord.dbd 1970-01-01 00:00:00 +0000
1695+++ src/std/rec/lsoRecord.dbd 2012-12-10 21:21:25 +0000
1696@@ -0,0 +1,112 @@
1697+#*************************************************************************
1698+# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
1699+# National Laboratory.
1700+# EPICS BASE is distributed subject to a Software License Agreement found
1701+# in file LICENSE that is included with this distribution.
1702+#*************************************************************************
1703+
1704+recordtype(lso) {
1705+ include "dbCommon.dbd"
1706+ %#include "devSup.h"
1707+ %
1708+ %/* Declare Device Support Entry Table */
1709+ %typedef struct lsodset {
1710+ % long number;
1711+ % DEVSUPFUN report;
1712+ % DEVSUPFUN init;
1713+ % DEVSUPFUN init_record;
1714+ % DEVSUPFUN get_ioint_info;
1715+ % DEVSUPFUN write_string;
1716+ %} lsodset;
1717+ %
1718+ field(VAL,DBF_NOACCESS) {
1719+ prompt("Current Value")
1720+ asl(ASL0)
1721+ pp(TRUE)
1722+ special(SPC_DBADDR)
1723+ extra("char *val")
1724+ }
1725+ field(OVAL,DBF_NOACCESS) {
1726+ prompt("Previous Value")
1727+ special(SPC_DBADDR)
1728+ interest(3)
1729+ extra("char *oval")
1730+ }
1731+ field(SIZV,DBF_USHORT) {
1732+ prompt("Size of buffers")
1733+ promptgroup(GUI_OUTPUT)
1734+ special(SPC_NOMOD)
1735+ interest(1)
1736+ initial("41")
1737+ }
1738+ field(LEN,DBF_ULONG) {
1739+ prompt("Length of VAL")
1740+ special(SPC_NOMOD)
1741+ }
1742+ field(OLEN,DBF_ULONG) {
1743+ prompt("Length of OVAL")
1744+ special(SPC_NOMOD)
1745+ interest(3)
1746+ }
1747+ field(DOL,DBF_INLINK) {
1748+ prompt("Desired Output Link")
1749+ promptgroup(GUI_OUTPUT)
1750+ interest(1)
1751+ }
1752+ field(IVOA,DBF_MENU) {
1753+ prompt("INVALID Output Action")
1754+ promptgroup(GUI_OUTPUT)
1755+ interest(2)
1756+ menu(menuIvoa)
1757+ }
1758+ field(IVOV,DBF_STRING) {
1759+ prompt("INVALID Output Value")
1760+ promptgroup(GUI_OUTPUT)
1761+ interest(2)
1762+ size(40)
1763+ }
1764+ field(OMSL,DBF_MENU) {
1765+ prompt("Output Mode Select")
1766+ promptgroup(GUI_OUTPUT)
1767+ interest(1)
1768+ menu(menuOmsl)
1769+ }
1770+ field(OUT,DBF_OUTLINK) {
1771+ prompt("Output Specification")
1772+ promptgroup(GUI_OUTPUT)
1773+ interest(1)
1774+ }
1775+ field(MPST,DBF_MENU) {
1776+ prompt("Post Value Monitors")
1777+ promptgroup(GUI_DISPLAY)
1778+ interest(1)
1779+ menu(menuPost)
1780+ }
1781+ field(APST,DBF_MENU) {
1782+ prompt("Post Archive Monitors")
1783+ promptgroup(GUI_DISPLAY)
1784+ interest(1)
1785+ menu(menuPost)
1786+ }
1787+ field(SIML,DBF_INLINK) {
1788+ prompt("Sim Mode link")
1789+ promptgroup(GUI_INPUTS)
1790+ interest(1)
1791+ }
1792+ field(SIMM,DBF_MENU) {
1793+ prompt("Simulation Mode")
1794+ interest(1)
1795+ menu(menuYesNo)
1796+ }
1797+ field(SIMS,DBF_MENU) {
1798+ prompt("Sim mode Alarm Svrty")
1799+ promptgroup(GUI_INPUTS)
1800+ interest(2)
1801+ menu(menuAlarmSevr)
1802+ }
1803+ field(SIOL,DBF_OUTLINK) {
1804+ prompt("Sim Output Specifctn")
1805+ promptgroup(GUI_INPUTS)
1806+ interest(1)
1807+ }
1808+}
1809
1810=== added file 'src/std/rec/printfRecord.c'
1811--- src/std/rec/printfRecord.c 1970-01-01 00:00:00 +0000
1812+++ src/std/rec/printfRecord.c 2012-12-10 21:21:25 +0000
1813@@ -0,0 +1,438 @@
1814+/*************************************************************************\
1815+* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
1816+* National Laboratory.
1817+* EPICS BASE is distributed subject to a Software License Agreement found
1818+* in file LICENSE that is included with this distribution.
1819+\*************************************************************************/
1820+
1821+/* Printf record type */
1822+/*
1823+ * Author: Andrew Johnson
1824+ * Date: 2012-09-18
1825+ */
1826+
1827+#include <stddef.h>
1828+#include <string.h>
1829+
1830+#include "dbDefs.h"
1831+#include "errlog.h"
1832+#include "alarm.h"
1833+#include "cantProceed.h"
1834+#include "dbAccess.h"
1835+#include "dbEvent.h"
1836+#include "dbFldTypes.h"
1837+#include "epicsMath.h"
1838+#include "epicsStdio.h"
1839+#include "errMdef.h"
1840+#include "recSup.h"
1841+#include "recGbl.h"
1842+#include "special.h"
1843+#define GEN_SIZE_OFFSET
1844+#include "printfRecord.h"
1845+#undef GEN_SIZE_OFFSET
1846+#include "epicsExport.h"
1847+
1848+
1849+/* Flag bits */
1850+#define F_CHAR 1
1851+#define F_SHORT 2
1852+#define F_LONG 4
1853+#define F_LEFT 8
1854+#define F_BADFMT 0x10
1855+#define F_BADLNK 0x20
1856+#define F_BAD (F_BADFMT | F_BADLNK)
1857+
1858+#define GET_PRINT(VALTYPE, DBRTYPE) \
1859+ VALTYPE val; \
1860+ int ok; \
1861+\
1862+ if (plink->type == CONSTANT) \
1863+ ok = recGblInitConstantLink(plink++, DBRTYPE, &val); \
1864+ else \
1865+ ok = ! dbGetLink(plink++, DBRTYPE, &val, 0, 0); \
1866+ if (ok) \
1867+ added = epicsSnprintf(pval, vspace + 1, format, val); \
1868+ else \
1869+ flags |= F_BADLNK
1870+
1871+static void doPrintf(printfRecord *prec)
1872+{
1873+ const char *pfmt = prec->fmt;
1874+ DBLINK *plink = &prec->inp0;
1875+ int linkn = 0;
1876+ char *pval = prec->val;
1877+ int vspace = prec->sizv - 1;
1878+ int ch;
1879+
1880+ while (vspace > 0 && (ch = *pfmt++)) {
1881+ if (ch != '%') {
1882+ /* Copy literal strings directly into prec->val */
1883+ *pval++ = ch;
1884+ --vspace;
1885+ }
1886+ else {
1887+ char format[20];
1888+ char *pformat = format;
1889+ int width = 0;
1890+ int precision = 0;
1891+ int *pnum = &width;
1892+ int flags = 0;
1893+ int added = 0;
1894+ int cont = 1;
1895+
1896+ /* The format directive parsing here is not comprehensive,
1897+ * in most cases we just copy each directive into format[]
1898+ * and get epicsSnprintf() do all the work. We do replace
1899+ * all variable-length field width or precision '*' chars
1900+ * with an integer read from the next input link, and we
1901+ * also convert %ls (long string) directives ourself, so
1902+ * we need to know the width, precision and justification.
1903+ */
1904+
1905+ *pformat++ = ch; /* '%' */
1906+ while (cont && (ch = *pfmt++)) {
1907+ *pformat++ = ch;
1908+ switch (ch) {
1909+ case '+': case ' ': case '#':
1910+ break;
1911+ case '-':
1912+ flags |= F_LEFT;
1913+ break;
1914+ case '.':
1915+ pnum = &precision;
1916+ break;
1917+ case '0': case '1': case '2': case '3': case '4':
1918+ case '5': case '6': case '7': case '8': case '9':
1919+ *pnum = *pnum * 10 + ch - '0';
1920+ break;
1921+ case '*':
1922+ if (*pnum) {
1923+ flags |= F_BADFMT;
1924+ }
1925+ else if (linkn++ < PRINTF_NLINKS) {
1926+ epicsInt16 i;
1927+ int ok;
1928+
1929+ if (plink->type == CONSTANT)
1930+ ok = recGblInitConstantLink(plink++, DBR_SHORT, &i);
1931+ else
1932+ ok = ! dbGetLink(plink++, DBR_SHORT, &i, 0, 0);
1933+ if (ok) {
1934+ *pnum = i;
1935+ added = epicsSnprintf(--pformat, 6, "%d", i);
1936+ pformat += added;
1937+ }
1938+ else /* No more LNKn fields */
1939+ flags |= F_BADLNK;
1940+ }
1941+ else
1942+ flags |= F_BADLNK;
1943+ break;
1944+ case 'h':
1945+ if (flags & F_SHORT)
1946+ flags = (flags & ~F_SHORT) | F_CHAR;
1947+ else
1948+ flags |= F_SHORT;
1949+ break;
1950+ case 'l':
1951+ flags |= F_LONG;
1952+ break;
1953+ default:
1954+ if (strchr("diouxXeEfFgGcs%", ch) == NULL)
1955+ flags |= F_BADFMT;
1956+ cont = 0;
1957+ break;
1958+ }
1959+ }
1960+ if (!ch) /* End of format string */
1961+ break;
1962+
1963+ if (flags & F_BAD)
1964+ goto bad_format;
1965+
1966+ *pformat = 0; /* Terminate our format string */
1967+
1968+ if (width < 0) {
1969+ width = -width;
1970+ flags |= F_LEFT;
1971+ }
1972+ if (precision < 0)
1973+ precision = 0;
1974+
1975+ if (ch == '%') {
1976+ added = epicsSnprintf(pval, vspace + 1, format);
1977+ }
1978+ else if (linkn++ >= PRINTF_NLINKS) {
1979+ /* No more LNKn fields */
1980+ flags |= F_BADLNK;
1981+ }
1982+ else
1983+ switch (ch) { /* Conversion character */
1984+ case 'c': case 'd': case 'i':
1985+ if (ch == 'c' || flags & F_CHAR) {
1986+ GET_PRINT(epicsInt8, DBR_CHAR);
1987+ }
1988+ else if (flags & F_SHORT) {
1989+ GET_PRINT(epicsInt16, DBR_SHORT);
1990+ }
1991+ else { /* F_LONG has no real effect */
1992+ GET_PRINT(epicsInt32, DBR_LONG);
1993+ }
1994+ break;
1995+
1996+ case 'o': case 'x': case 'X': case 'u':
1997+ if (flags & F_CHAR) {
1998+ GET_PRINT(epicsUInt8, DBR_UCHAR);
1999+ }
2000+ else if (flags & F_SHORT) {
2001+ GET_PRINT(epicsUInt16, DBR_USHORT);
2002+ }
2003+ else { /* F_LONG has no real effect */
2004+ GET_PRINT(epicsUInt32, DBR_ULONG);
2005+ }
2006+ break;
2007+
2008+ case 'e': case 'E':
2009+ case 'f': case 'F':
2010+ case 'g': case 'G':
2011+ if (flags & F_SHORT) {
2012+ GET_PRINT(epicsFloat32, DBR_FLOAT);
2013+ }
2014+ else {
2015+ GET_PRINT(epicsFloat64, DBR_DOUBLE);
2016+ }
2017+ break;
2018+
2019+ case 's':
2020+ if (flags & F_LONG && plink->type != CONSTANT) {
2021+ long n = vspace + 1;
2022+
2023+ if (precision && n > precision)
2024+ n = precision + 1;
2025+ /* If set, precision is the maximum number of
2026+ * characters to be printed from the string.
2027+ * It does not limit the field width however.
2028+ */
2029+ if (dbGetLink(plink++, DBR_CHAR, pval, 0, &n))
2030+ flags |= F_BADLNK;
2031+ else {
2032+ int padding;
2033+
2034+ /* Terminate string and measure its length */
2035+ pval[n] = 0;
2036+ added = strlen(pval);
2037+ padding = width - added;
2038+
2039+ if (padding > 0) {
2040+ if (flags & F_LEFT) {
2041+ /* add spaces on RHS */
2042+ if (width > vspace)
2043+ padding = vspace - added;
2044+ memset(pval + added, ' ', padding);
2045+ }
2046+ else {
2047+ /* insert spaces on LHS */
2048+ int trunc = width - vspace;
2049+
2050+ if (trunc < added) {
2051+ added -= trunc;
2052+ memmove(pval + padding, pval, added);
2053+ }
2054+ else {
2055+ padding = vspace;
2056+ added = 0;
2057+ }
2058+ memset(pval, ' ', padding);
2059+ }
2060+ added += padding;
2061+ }
2062+ }
2063+ }
2064+ else {
2065+ char val[MAX_STRING_SIZE];
2066+ int ok;
2067+
2068+ if (plink->type == CONSTANT)
2069+ ok = recGblInitConstantLink(plink++, DBR_STRING, val);
2070+ else
2071+ ok = ! dbGetLink(plink++, DBR_STRING, val, 0, 0);
2072+ if (ok)
2073+ added = epicsSnprintf(pval, vspace + 1, format, val);
2074+ else
2075+ flags |= F_BADLNK;
2076+ }
2077+ break;
2078+
2079+ default:
2080+ errlogPrintf("printfRecord: Unexpected conversion '%s'\n",
2081+ format);
2082+ flags |= F_BADFMT;
2083+ break;
2084+ }
2085+
2086+ if (flags & F_BAD) {
2087+ bad_format:
2088+ added = epicsSnprintf(pval, vspace + 1, "%s",
2089+ flags & F_BADLNK ? prec->ivls : format);
2090+ }
2091+
2092+ if (added <= vspace) {
2093+ pval += added;
2094+ vspace -= added;
2095+ }
2096+ else {
2097+ /* Output was truncated */
2098+ pval += vspace;
2099+ vspace = 0;
2100+ }
2101+ }
2102+ }
2103+ *pval++ = 0; /* Terminate the VAL string */
2104+ prec->len = pval - prec->val;
2105+}
2106+
2107+
2108+static long init_record(printfRecord *prec, int pass)
2109+{
2110+ printfdset *pdset;
2111+
2112+ if (pass == 0) {
2113+ size_t sizv = prec->sizv;
2114+
2115+ if (sizv < 16) {
2116+ sizv = 16; /* Enforce a minimum size for the VAL field */
2117+ prec->sizv = sizv;
2118+ }
2119+
2120+ prec->val = callocMustSucceed(1, sizv, "printf::init_record");
2121+ prec->len = 0;
2122+ return 0;
2123+ }
2124+
2125+ pdset = (printfdset *) prec->dset;
2126+ if (!pdset)
2127+ return 0; /* Device support is optional */
2128+
2129+ if (pdset->number < 5) {
2130+ recGblRecordError(S_dev_missingSup, prec, "printf::init_record");
2131+ return S_dev_missingSup;
2132+ }
2133+
2134+ if (pdset->init_record) {
2135+ long status = pdset->init_record(prec);
2136+ if (status)
2137+ return status;
2138+ }
2139+
2140+ return 0;
2141+}
2142+
2143+static long process(printfRecord *prec)
2144+{
2145+ int pact = prec->pact;
2146+ printfdset *pdset;
2147+ long status = 0;
2148+ epicsUInt16 events;
2149+
2150+ if (!pact) {
2151+ doPrintf(prec);
2152+
2153+ prec->udf = FALSE;
2154+ recGblGetTimeStamp(prec);
2155+ }
2156+
2157+ /* Call device support */
2158+ pdset = (printfdset *) prec->dset;
2159+ if (pdset &&
2160+ pdset->number >= 5 &&
2161+ pdset->write_string) {
2162+ status = pdset->write_string(prec);
2163+
2164+ /* Asynchronous if device support set pact */
2165+ if (!pact && prec->pact)
2166+ return status;
2167+ }
2168+
2169+ prec->pact = TRUE;
2170+
2171+ /* Post monitor */
2172+ events = recGblResetAlarms(prec);
2173+ db_post_events(prec, prec->val, events | DBE_VALUE | DBE_LOG);
2174+ db_post_events(prec, &prec->len, events | DBE_VALUE | DBE_LOG);
2175+
2176+ /* Wrap up */
2177+ recGblFwdLink(prec);
2178+ prec->pact = FALSE;
2179+ return status;
2180+}
2181+
2182+static long cvt_dbaddr(DBADDR *paddr)
2183+{
2184+ printfRecord *prec = (printfRecord *)paddr->precord;
2185+ int fieldIndex = dbGetFieldIndex(paddr);
2186+
2187+ if (fieldIndex == printfRecordVAL) {
2188+ paddr->pfield = prec->val;
2189+ paddr->no_elements = 1;
2190+ paddr->field_type = DBF_STRING;
2191+ paddr->dbr_field_type = DBF_STRING;
2192+ paddr->field_size = prec->sizv;
2193+ }
2194+ else
2195+ errlogPrintf("printfRecord::cvt_dbaddr called for %s.%s\n",
2196+ prec->name, paddr->pfldDes->name);
2197+ return 0;
2198+}
2199+
2200+static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
2201+{
2202+ printfRecord *prec = (printfRecord *) paddr->precord;
2203+
2204+ *no_elements = prec->len;
2205+ *offset = 0;
2206+ return 0;
2207+}
2208+
2209+
2210+/* Create Record Support Entry Table */
2211+
2212+#define report NULL
2213+#define initialize NULL
2214+/* init_record */
2215+/* process */
2216+#define special NULL
2217+#define get_value NULL
2218+/* cvt_dbaddr */
2219+/* get_array_info */
2220+#define put_array_info NULL
2221+#define get_units NULL
2222+#define get_precision NULL
2223+#define get_enum_str NULL
2224+#define get_enum_strs NULL
2225+#define put_enum_str NULL
2226+#define get_graphic_double NULL
2227+#define get_control_double NULL
2228+#define get_alarm_double NULL
2229+
2230+rset printfRSET = {
2231+ RSETNUMBER,
2232+ report,
2233+ initialize,
2234+ init_record,
2235+ process,
2236+ special,
2237+ get_value,
2238+ cvt_dbaddr,
2239+ get_array_info,
2240+ put_array_info,
2241+ get_units,
2242+ get_precision,
2243+ get_enum_str,
2244+ get_enum_strs,
2245+ put_enum_str,
2246+ get_graphic_double,
2247+ get_control_double,
2248+ get_alarm_double
2249+};
2250+epicsExportAddress(rset, printfRSET);
2251+
2252
2253=== added file 'src/std/rec/printfRecord.dbd'
2254--- src/std/rec/printfRecord.dbd 1970-01-01 00:00:00 +0000
2255+++ src/std/rec/printfRecord.dbd 2012-12-10 21:21:25 +0000
2256@@ -0,0 +1,109 @@
2257+#*************************************************************************
2258+# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
2259+# National Laboratory.
2260+# EPICS BASE is distributed subject to a Software License Agreement found
2261+# in file LICENSE that is included with this distribution.
2262+#*************************************************************************
2263+
2264+recordtype(printf) {
2265+ include "dbCommon.dbd"
2266+ %#include "devSup.h"
2267+ %
2268+ %/* Declare Device Support Entry Table */
2269+ %typedef struct printfdset {
2270+ % long number;
2271+ % DEVSUPFUN report;
2272+ % DEVSUPFUN init;
2273+ % DEVSUPFUN init_record;
2274+ % DEVSUPFUN get_ioint_info;
2275+ % DEVSUPFUN write_string;
2276+ %} printfdset;
2277+ %
2278+ field(VAL,DBF_NOACCESS) {
2279+ prompt("Result")
2280+ asl(ASL0)
2281+ pp(TRUE)
2282+ special(SPC_DBADDR)
2283+ extra("char *val")
2284+ }
2285+ field(SIZV,DBF_USHORT) {
2286+ prompt("Size of VAL buffer")
2287+ promptgroup(GUI_OUTPUT)
2288+ special(SPC_NOMOD)
2289+ interest(1)
2290+ initial("41")
2291+ }
2292+ field(LEN,DBF_ULONG) {
2293+ prompt("Length of VAL")
2294+ special(SPC_NOMOD)
2295+ }
2296+ field(OUT,DBF_OUTLINK) {
2297+ prompt("Output Specification")
2298+ promptgroup(GUI_OUTPUT)
2299+ interest(1)
2300+ }
2301+ field(FMT,DBF_STRING) {
2302+ prompt("Format String")
2303+ promptgroup(GUI_CALC)
2304+ pp(TRUE)
2305+ size(81)
2306+ }
2307+ field(IVLS,DBF_STRING) {
2308+ prompt("Invalid Link String")
2309+ promptgroup(GUI_CALC)
2310+ size(16)
2311+ initial("LNK")
2312+ }
2313+ field(INP0,DBF_INLINK) {
2314+ prompt("Input 0")
2315+ promptgroup(GUI_INPUTS)
2316+ interest(1)
2317+ }
2318+ field(INP1,DBF_INLINK) {
2319+ prompt("Input 1")
2320+ promptgroup(GUI_INPUTS)
2321+ interest(1)
2322+ }
2323+ field(INP2,DBF_INLINK) {
2324+ prompt("Input 2")
2325+ promptgroup(GUI_INPUTS)
2326+ interest(1)
2327+ }
2328+ field(INP3,DBF_INLINK) {
2329+ prompt("Input 3")
2330+ promptgroup(GUI_INPUTS)
2331+ interest(1)
2332+ }
2333+ field(INP4,DBF_INLINK) {
2334+ prompt("Input 4")
2335+ promptgroup(GUI_INPUTS)
2336+ interest(1)
2337+ }
2338+ field(INP5,DBF_INLINK) {
2339+ prompt("Input 5")
2340+ promptgroup(GUI_INPUTS)
2341+ interest(1)
2342+ }
2343+ field(INP6,DBF_INLINK) {
2344+ prompt("Input 6")
2345+ promptgroup(GUI_INPUTS)
2346+ interest(1)
2347+ }
2348+ field(INP7,DBF_INLINK) {
2349+ prompt("Input 7")
2350+ promptgroup(GUI_INPUTS)
2351+ interest(1)
2352+ }
2353+ field(INP8,DBF_INLINK) {
2354+ prompt("Input 8")
2355+ promptgroup(GUI_INPUTS)
2356+ interest(1)
2357+ }
2358+ field(INP9,DBF_INLINK) {
2359+ prompt("Input 9")
2360+ promptgroup(GUI_INPUTS)
2361+ interest(1)
2362+ }
2363+ %/* Number of INPx fields defined */
2364+ %#define PRINTF_NLINKS 10
2365+}

Subscribers

People subscribed via source and target branches

to all changes: