This is Unofficial EPICS BASE Doxygen Site
lsoRecord.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 Output record type */
9 /*
10  * Author: Andrew Johnson
11  * Date: 2012-11-28
12  */
13 
14 
15 #include <stddef.h>
16 #include <stdio.h>
17 #include <string.h>
18 
19 #include "dbDefs.h"
20 #include "errlog.h"
21 #include "alarm.h"
22 #include "callback.h"
23 #include "cantProceed.h"
24 #include "dbAccess.h"
25 #include "dbEvent.h"
26 #include "dbFldTypes.h"
27 #include "devSup.h"
28 #include "errMdef.h"
29 #include "menuIvoa.h"
30 #include "menuOmsl.h"
31 #include "menuPost.h"
32 #include "menuYesNo.h"
33 #include "recSup.h"
34 #include "recGbl.h"
35 #include "special.h"
36 #define GEN_SIZE_OFFSET
37 #include "lsoRecord.h"
38 #undef GEN_SIZE_OFFSET
39 #include "epicsExport.h"
40 
41 static void monitor(lsoRecord *);
42 static long writeValue(lsoRecord *);
43 
44 static long init_record(struct dbCommon *pcommon, int pass)
45 {
46  struct lsoRecord *prec = (struct lsoRecord *)pcommon;
47  lsodset *pdset;
48 
49  if (pass == 0) {
50  size_t sizv = prec->sizv;
51 
52  if (sizv < 16) {
53  sizv = 16; /* Enforce a minimum size for the VAL field */
54  prec->sizv = sizv;
55  }
56 
57  prec->val = callocMustSucceed(1, sizv, "lso::init_record");
58  prec->len = 0;
59  prec->oval = callocMustSucceed(1, sizv, "lso::init_record");
60  prec->olen = 0;
61  return 0;
62  }
63 
64  recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
65 
66  pdset = (lsodset *) prec->dset;
67  if (!pdset) {
68  recGblRecordError(S_dev_noDSET, prec, "lso: init_record");
69  return S_dev_noDSET;
70  }
71 
72  /* must have a write_string function defined */
73  if (pdset->common.number < 5 || !pdset->write_string) {
74  recGblRecordError(S_dev_missingSup, prec, "lso: init_record");
75  return S_dev_missingSup;
76  }
77 
78  dbLoadLinkLS(&prec->dol, prec->val, prec->sizv, &prec->len);
79 
80  if (pdset->common.init_record) {
81  long status = pdset->common.init_record(pcommon);
82 
83  if (status)
84  return status;
85  }
86 
87  if (prec->len) {
88  strcpy(prec->oval, prec->val);
89  prec->olen = prec->len;
90  prec->udf = FALSE;
91  }
92 
93  return 0;
94 }
95 
96 static long process(struct dbCommon *pcommon)
97 {
98  struct lsoRecord *prec = (struct lsoRecord *)pcommon;
99  int pact = prec->pact;
100  lsodset *pdset = (lsodset *) prec->dset;
101  long status = 0;
102 
103  if (!pdset || !pdset->write_string) {
104  prec->pact = TRUE;
105  recGblRecordError(S_dev_missingSup, prec, "lso: write_string");
106  return S_dev_missingSup;
107  }
108 
109  if (!pact && prec->omsl == menuOmslclosed_loop)
110  if (!dbGetLinkLS(&prec->dol, prec->val, prec->sizv, &prec->len))
111  prec->udf = FALSE;
112 
113  if (prec->udf)
114  recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM);
115 
116  if (prec->nsev < INVALID_ALARM )
117  status = writeValue(prec); /* write the new value */
118  else {
119  switch (prec->ivoa) {
120  case menuIvoaContinue_normally:
121  status = writeValue(prec); /* write the new value */
122  break;
123 
124  case menuIvoaDon_t_drive_outputs:
125  break;
126 
127  case menuIvoaSet_output_to_IVOV:
128  if (!prec->pact) {
129  size_t size = prec->sizv - 1;
130 
131  strncpy(prec->val, prec->ivov, size);
132  prec->val[size] = 0;
133  prec->len = strlen(prec->val) + 1;
134  }
135  status = writeValue(prec); /* write the new value */
136  break;
137 
138  default:
139  status = -1;
140  recGblRecordError(S_db_badField, prec,
141  "lso:process Bad IVOA choice");
142  }
143  }
144 
145  /* Asynchronous if device support set pact */
146  if (!pact && prec->pact)
147  return status;
148 
149  prec->pact = TRUE;
150  recGblGetTimeStampSimm(prec, prec->simm, NULL);
151 
152  monitor(prec);
153 
154  /* Wrap up */
155  recGblFwdLink(prec);
156  prec->pact = FALSE;
157  return status;
158 }
159 
160 static long cvt_dbaddr(DBADDR *paddr)
161 {
162  lsoRecord *prec = (lsoRecord *) paddr->precord;
163  int fieldIndex = dbGetFieldIndex(paddr);
164 
165  if (fieldIndex == lsoRecordVAL) {
166  paddr->pfield = prec->val;
167  paddr->special = SPC_MOD;
168  }
169  else if (fieldIndex == lsoRecordOVAL) {
170  paddr->pfield = prec->oval;
171  paddr->special = SPC_NOMOD;
172  }
173  else {
174  errlogPrintf("lsoRecord::cvt_dbaddr called for %s.%s\n",
175  prec->name, paddr->pfldDes->name);
176  return -1;
177  }
178 
179  paddr->no_elements = 1;
180  paddr->field_type = DBF_STRING;
181  paddr->dbr_field_type = DBF_STRING;
182  paddr->field_size = prec->sizv;
183  return 0;
184 }
185 
186 static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
187 {
188  lsoRecord *prec = (lsoRecord *) paddr->precord;
189  int fieldIndex = dbGetFieldIndex(paddr);
190 
191  if (fieldIndex == lsoRecordVAL)
192  *no_elements = prec->len;
193  else if (fieldIndex == lsoRecordOVAL)
194  *no_elements = prec->olen;
195  else
196  return -1;
197 
198  *offset = 0;
199  return 0;
200 }
201 
202 static long put_array_info(DBADDR *paddr, long nNew)
203 {
204  lsoRecord *prec = (lsoRecord *) paddr->precord;
205 
206  if (nNew >= prec->sizv)
207  nNew = prec->sizv - 1; /* truncated string */
208  if (paddr->field_type == DBF_CHAR)
209  prec->val[nNew] = 0; /* ensure data is terminated */
210 
211  return 0;
212 }
213 
214 static long special(DBADDR *paddr, int after)
215 {
216  lsoRecord *prec = (lsoRecord *) paddr->precord;
217  int special_type = paddr->special;
218 
219  if (special_type == SPC_MOD && dbGetFieldIndex(paddr) == lsoRecordSIMM) {
220  if (!after)
221  recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
222  else
223  recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
224  return 0;
225  }
226 
227  if (!after)
228  return 0;
229 
230  /* We set prec->len here and not in put_array_info()
231  * because that does not get called if the put was
232  * done using a DBR_STRING type.
233  */
234  prec->len = strlen(prec->val) + 1;
235  db_post_events(prec, &prec->len, DBE_VALUE | DBE_LOG);
236 
237  return 0;
238 }
239 
240 static void monitor(lsoRecord *prec)
241 {
242  epicsUInt16 events = recGblResetAlarms(prec);
243 
244  if (prec->len != prec->olen ||
245  memcmp(prec->oval, prec->val, prec->len)) {
246  events |= DBE_VALUE | DBE_LOG;
247  memcpy(prec->oval, prec->val, prec->len);
248  }
249 
250  if (prec->len != prec->olen) {
251  prec->olen = prec->len;
252  db_post_events(prec, &prec->len, DBE_VALUE | DBE_LOG);
253  }
254 
255  if (prec->mpst == menuPost_Always)
256  events |= DBE_VALUE;
257  if (prec->apst == menuPost_Always)
258  events |= DBE_LOG;
259 
260  if (events)
261  db_post_events(prec, prec->val, events);
262 }
263 
264 static long writeValue(lsoRecord *prec)
265 {
266  lsodset *pdset = (lsodset *) prec->dset;
267  long status = 0;
268 
269  if (!prec->pact) {
270  status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
271  if (status) return status;
272  }
273 
274  switch (prec->simm) {
275  case menuYesNoNO:
276  status = pdset->write_string(prec);
277  break;
278 
279  case menuYesNoYES: {
280  recGblSetSevr(prec, SIMM_ALARM, prec->sims);
281  if (prec->pact || (prec->sdly < 0.)) {
282  status = dbPutLinkLS(&prec->siol, prec->val, prec->len);
283  prec->pact = FALSE;
284  } else { /* !prec->pact && delay >= 0. */
285  epicsCallback *pvt = prec->simpvt;
286  if (!pvt) {
287  pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */
288  prec->simpvt = pvt;
289  }
290  if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
291  prec->pact = TRUE;
292  }
293  break;
294  }
295 
296  default:
297  recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
298  status = -1;
299  }
300 
301  return status;
302 }
303 
304 /* Create Record Support Entry Table*/
305 
306 #define report NULL
307 #define initialize NULL
308 /* init_record */
309 /* process */
310 /* special */
311 #define get_value NULL
312 /* cvt_dbaddr */
313 /* get_array_info */
314 /* put_array_info */
315 #define get_units NULL
316 #define get_precision NULL
317 #define get_enum_str NULL
318 #define get_enum_strs NULL
319 #define put_enum_str NULL
320 #define get_graphic_double NULL
321 #define get_control_double NULL
322 #define get_alarm_double NULL
323 
325  RSETNUMBER,
326  report,
327  initialize,
328  init_record,
329  process,
330  special,
331  get_value,
332  cvt_dbaddr,
335  get_units,
337  get_enum_str,
339  put_enum_str,
343 };
344 epicsExportAddress(rset, lsoRSET);
#define RSETNUMBER
Definition: recSup.h:92
#define FALSE
Definition: dbDefs.h:32
#define get_enum_strs
Definition: lsoRecord.c:318
#define get_value
Definition: lsoRecord.c:311
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 NULL
Definition: catime.c:38
#define get_enum_str
Definition: lsoRecord.c:317
Miscellaneous macro definitions.
#define put_enum_str
Definition: lsoRecord.c:319
epicsExportAddress(rset, lsoRSET)
#define report
Definition: lsoRecord.c:306
#define DBE_VALUE
Definition: caeventmask.h:38
#define get_array_info
Definition: aiRecord.c:56
Device support routines.
#define DBE_LOG
Definition: caeventmask.h:40
#define SIMM_ALARM
Definition: alarm.h:110
#define get_graphic_double
Definition: lsoRecord.c:320
#define get_units
Definition: lsoRecord.c:315
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 get_control_double
Definition: lsoRecord.c:321
#define initialize
Definition: lsoRecord.c:307
#define put_array_info
Definition: aiRecord.c:57
#define TRUE
Definition: dbDefs.h:27
if(yy_init)
Definition: scan.c:972
#define get_alarm_double
Definition: lsoRecord.c:322
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 INVALID_ALARM
Definition: alarm.h:53
#define cvt_dbaddr
Definition: aiRecord.c:55
#define special
Definition: dfanoutRecord.c:50
rset lsoRSET
Definition: lsoRecord.c:324
#define S_dev_noDSET
Definition: devSup.h:169
#define UDF_ALARM
Definition: alarm.h:108
#define get_precision
Definition: lsoRecord.c:316
Exporting IOC objects.