This is Unofficial EPICS BASE Doxygen Site
lsiRecord.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
3 * National Laboratory.
4 * EPICS BASE is distributed subject to a Software License Agreement found
5 * in file LICENSE that is included with this distribution.
6 \*************************************************************************/
7 
8 /* Long String Input record type */
9 /*
10  * Author: Andrew Johnson
11  * Date: 2012-11-27
12  */
13 
14 #include <stddef.h>
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include "dbDefs.h"
19 #include "errlog.h"
20 #include "alarm.h"
21 #include "callback.h"
22 #include "cantProceed.h"
23 #include "dbAccess.h"
24 #include "dbEvent.h"
25 #include "dbFldTypes.h"
26 #include "errMdef.h"
27 #include "menuPost.h"
28 #include "menuYesNo.h"
29 #include "recSup.h"
30 #include "recGbl.h"
31 #include "special.h"
32 #define GEN_SIZE_OFFSET
33 #include "lsiRecord.h"
34 #undef GEN_SIZE_OFFSET
35 #include "epicsExport.h"
36 
37 static void monitor(lsiRecord *);
38 static long readValue(lsiRecord *);
39 
40 static long init_record(struct dbCommon *pcommon, int pass)
41 {
42  struct lsiRecord *prec = (struct lsiRecord *)pcommon;
43  lsidset *pdset;
44 
45  if (pass == 0) {
46  size_t sizv = prec->sizv;
47 
48  if (sizv < 16) {
49  sizv = 16; /* Enforce a minimum size for the VAL field */
50  prec->sizv = sizv;
51  }
52 
53  prec->val = callocMustSucceed(1, sizv, "lsi::init_record");
54  prec->len = 0;
55  prec->oval = callocMustSucceed(1, sizv, "lsi::init_record");
56  prec->olen = 0;
57  return 0;
58  }
59 
60  recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
61 
62  pdset = (lsidset *) prec->dset;
63  if (!pdset) {
64  recGblRecordError(S_dev_noDSET, prec, "lsi: init_record");
65  return S_dev_noDSET;
66  }
67 
68  /* must have a read_string function */
69  if (pdset->common.number < 5 || !pdset->read_string) {
70  recGblRecordError(S_dev_missingSup, prec, "lsi: init_record");
71  return S_dev_missingSup;
72  }
73 
74  if (pdset->common.init_record) {
75  long status = pdset->common.init_record(pcommon);
76 
77  if (status)
78  return status;
79  }
80 
81  if (prec->len) {
82  strcpy(prec->oval, prec->val);
83  prec->olen = prec->len;
84  prec->udf = FALSE;
85  }
86 
87  return 0;
88 }
89 
90 static long process(struct dbCommon *pcommon)
91 {
92  struct lsiRecord *prec = (struct lsiRecord *)pcommon;
93  int pact = prec->pact;
94  lsidset *pdset = (lsidset *) prec->dset;
95  long status = 0;
96 
97  if (!pdset || !pdset->read_string) {
98  prec->pact = TRUE;
99  recGblRecordError(S_dev_missingSup, prec, "lsi: read_string");
100  return S_dev_missingSup;
101  }
102 
103  status = readValue(prec); /* read the new value */
104  if (!pact && prec->pact)
105  return 0;
106 
107  prec->pact = TRUE;
108  recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
109 
110  monitor(prec);
111 
112  /* Wrap up */
113  recGblFwdLink(prec);
114  prec->pact = FALSE;
115  return status;
116 }
117 
118 static long cvt_dbaddr(DBADDR *paddr)
119 {
120  lsiRecord *prec = (lsiRecord *) paddr->precord;
121  int fieldIndex = dbGetFieldIndex(paddr);
122 
123  if (fieldIndex == lsiRecordVAL) {
124  paddr->pfield = prec->val;
125  paddr->special = SPC_MOD;
126  }
127  else if (fieldIndex == lsiRecordOVAL) {
128  paddr->pfield = prec->oval;
129  paddr->special = SPC_NOMOD;
130  }
131  else {
132  errlogPrintf("lsiRecord::cvt_dbaddr called for %s.%s\n",
133  prec->name, paddr->pfldDes->name);
134  return -1;
135  }
136 
137  paddr->no_elements = 1;
138  paddr->field_type = DBF_STRING;
139  paddr->dbr_field_type = DBF_STRING;
140  paddr->field_size = prec->sizv;
141  return 0;
142 }
143 
144 static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
145 {
146  lsiRecord *prec = (lsiRecord *) paddr->precord;
147  int fieldIndex = dbGetFieldIndex(paddr);
148 
149  if (fieldIndex == lsiRecordVAL)
150  *no_elements = prec->len;
151  else if (fieldIndex == lsiRecordOVAL)
152  *no_elements = prec->olen;
153  else
154  return -1;
155 
156  *offset = 0;
157  return 0;
158 }
159 
160 static long put_array_info(DBADDR *paddr, long nNew)
161 {
162  lsiRecord *prec = (lsiRecord *) paddr->precord;
163 
164  if (nNew >= prec->sizv)
165  nNew = prec->sizv - 1; /* truncated string */
166  if (paddr->field_type == DBF_CHAR)
167  prec->val[nNew] = 0; /* ensure data is terminated */
168 
169  return 0;
170 }
171 
172 static long special(DBADDR *paddr, int after)
173 {
174  lsiRecord *prec = (lsiRecord *) paddr->precord;
175  int special_type = paddr->special;
176 
177  if (special_type == SPC_MOD && dbGetFieldIndex(paddr) == lsiRecordSIMM) {
178  if (!after)
179  recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
180  else
181  recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
182  return 0;
183  }
184 
185  if (!after)
186  return 0;
187 
188  /* We set prec->len here and not in put_array_info()
189  * because that does not get called if the put was
190  * done using a DBR_STRING type.
191  */
192  prec->len = strlen(prec->val) + 1;
193  db_post_events(prec, &prec->len, DBE_VALUE | DBE_LOG);
194 
195  return 0;
196 }
197 
198 static void monitor(lsiRecord *prec)
199 {
200  epicsUInt16 events = recGblResetAlarms(prec);
201 
202  if (prec->len != prec->olen ||
203  memcmp(prec->oval, prec->val, prec->len)) {
204  events |= DBE_VALUE | DBE_LOG;
205  memcpy(prec->oval, prec->val, prec->len);
206  }
207 
208  if (prec->len != prec->olen) {
209  prec->olen = prec->len;
210  db_post_events(prec, &prec->len, DBE_VALUE | DBE_LOG);
211  }
212 
213  if (prec->mpst == menuPost_Always)
214  events |= DBE_VALUE;
215  if (prec->apst == menuPost_Always)
216  events |= DBE_LOG;
217 
218  if (events)
219  db_post_events(prec, prec->val, events);
220 }
221 
222 static long readValue(lsiRecord *prec)
223 {
224  lsidset *pdset = (lsidset *) prec->dset;
225  long status = 0;
226 
227  if (!prec->pact) {
228  status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
229  if (status) return status;
230  }
231 
232  switch (prec->simm) {
233  case menuYesNoNO:
234  status = pdset->read_string(prec);
235  break;
236 
237  case menuYesNoYES: {
238  recGblSetSevr(prec, SIMM_ALARM, prec->sims);
239  if (prec->pact || (prec->sdly < 0.)) {
240  status = dbGetLinkLS(&prec->siol, prec->val, prec->sizv, &prec->len);
241  if (status == 0) prec->udf = FALSE;
242  prec->pact = FALSE;
243  } else { /* !prec->pact && delay >= 0. */
244  epicsCallback *pvt = prec->simpvt;
245  if (!pvt) {
246  pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */
247  prec->simpvt = pvt;
248  }
249  if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
250  prec->pact = TRUE;
251  }
252  break;
253  }
254 
255  default:
256  recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
257  status = -1;
258  }
259 
260  return status;
261 }
262 
263 /* Create Record Support Entry Table */
264 
265 #define report NULL
266 #define initialize NULL
267 /* init_record */
268 /* process */
269 /* special */
270 #define get_value NULL
271 /* cvt_dbaddr */
272 /* get_array_info */
273 /* put_array_info */
274 #define get_units NULL
275 #define get_precision NULL
276 #define get_enum_str NULL
277 #define get_enum_strs NULL
278 #define put_enum_str NULL
279 #define get_graphic_double NULL
280 #define get_control_double NULL
281 #define get_alarm_double NULL
282 
284  RSETNUMBER,
285  report,
286  initialize,
287  init_record,
288  process,
289  special,
290  get_value,
291  cvt_dbaddr,
294  get_units,
296  get_enum_str,
298  put_enum_str,
302 };
303 epicsExportAddress(rset, lsiRSET);
#define get_enum_str
Definition: lsiRecord.c:276
#define RSETNUMBER
Definition: recSup.h:92
#define FALSE
Definition: dbDefs.h:32
pvd::Status status
#define SPC_NOMOD
Definition: special.h:26
unsigned short epicsUInt16
Definition: epicsTypes.h:41
#define init_record
#define S_dev_missingSup
Definition: devSup.h:170
#define SOFT_ALARM
Definition: alarm.h:106
#define get_precision
Definition: lsiRecord.c:275
epicsExportAddress(rset, lsiRSET)
Miscellaneous macro definitions.
#define get_enum_strs
Definition: lsiRecord.c:277
#define get_value
Definition: lsiRecord.c:270
#define initialize
Definition: lsiRecord.c:266
#define DBE_VALUE
Definition: caeventmask.h:38
#define get_array_info
Definition: aiRecord.c:56
#define get_graphic_double
Definition: lsiRecord.c:279
#define DBE_LOG
Definition: caeventmask.h:40
rset lsiRSET
Definition: lsiRecord.c:283
#define SIMM_ALARM
Definition: alarm.h:110
#define get_control_double
Definition: lsiRecord.c:280
LIBCOM_API void * callocMustSucceed(size_t count, size_t size, const char *msg)
A calloc() that never returns NULL.
Definition: cantProceed.c:22
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
#define put_enum_str
Definition: lsiRecord.c:278
#define report
Definition: lsiRecord.c:265
#define get_alarm_double
Definition: lsiRecord.c:281
#define put_array_info
Definition: aiRecord.c:57
#define TRUE
Definition: dbDefs.h:27
if(yy_init)
Definition: scan.c:972
Definition: recSup.h:67
#define SPC_MOD
Definition: special.h:33
Routines for code that can&#39;t continue or return after an error.
int prec
Definition: reader.c:29
#define get_units
Definition: lsiRecord.c:274
#define INVALID_ALARM
Definition: alarm.h:53
#define cvt_dbaddr
Definition: aiRecord.c:55
#define special
Definition: dfanoutRecord.c:50
#define S_dev_noDSET
Definition: devSup.h:169
Exporting IOC objects.