This is Unofficial EPICS BASE Doxygen Site
waveformRecord.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 
10 /* recWaveform.c - Record Support Routines for Waveform records */
11 /*
12  * Original Author: Bob Dalesio
13  * Date: 7-14-89
14  */
15 
16 #include <stddef.h>
17 #include <stdlib.h>
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <string.h>
21 
22 #include "dbDefs.h"
23 #include "epicsPrint.h"
24 #include "epicsString.h"
25 #include "alarm.h"
26 #include "callback.h"
27 #include "dbAccess.h"
28 #include "dbEvent.h"
29 #include "dbFldTypes.h"
30 #include "dbScan.h"
31 #include "devSup.h"
32 #include "errMdef.h"
33 #include "recSup.h"
34 #include "recGbl.h"
35 #include "special.h"
36 #include "cantProceed.h"
37 #include "menuYesNo.h"
38 
39 #define GEN_SIZE_OFFSET
40 #include "waveformRecord.h"
41 #undef GEN_SIZE_OFFSET
42 #include "epicsExport.h"
43 
44 /* Create RSET - Record Support Entry Table*/
45 #define report NULL
46 #define initialize NULL
47 static long init_record(struct dbCommon *, int);
48 static long process(struct dbCommon *);
49 static long special(DBADDR *, int);
50 #define get_value NULL
51 static long cvt_dbaddr(DBADDR *);
52 static long get_array_info(DBADDR *, long *, long *);
53 static long put_array_info(DBADDR *, long);
54 static long get_units(DBADDR *, char *);
55 static long get_precision(const DBADDR *, long *);
56 #define get_enum_str NULL
57 #define get_enum_strs NULL
58 #define put_enum_str NULL
59 static long get_graphic_double(DBADDR *, struct dbr_grDouble *);
60 static long get_control_double(DBADDR *, struct dbr_ctrlDouble *);
61 #define get_alarm_double NULL
63  RSETNUMBER,
64  report,
65  initialize,
67  process,
68  special,
69  get_value,
70  cvt_dbaddr,
73  get_units,
81 };
82 epicsExportAddress(rset,waveformRSET);
83 
84 static void monitor(waveformRecord *);
85 static long readValue(waveformRecord *);
86 
87 static long init_record(struct dbCommon *pcommon, int pass)
88 {
89  struct waveformRecord *prec = (struct waveformRecord *)pcommon;
90  wfdset *pdset;
91 
92  if (pass == 0) {
93  if (prec->nelm <= 0)
94  prec->nelm = 1;
95  if (prec->ftvl > DBF_ENUM)
96  prec->ftvl = DBF_UCHAR;
97  prec->bptr = callocMustSucceed(prec->nelm, dbValueSize(prec->ftvl),
98  "waveform calloc failed");
99  prec->nord = (prec->nelm == 1);
100  return 0;
101  }
102 
103  recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
104 
105  /* must have dset defined */
106  if (!(pdset = (wfdset *)(prec->dset))) {
107  recGblRecordError(S_dev_noDSET,(void *)prec,"wf: init_record");
108  return S_dev_noDSET;
109  }
110  /* must have read_wf function defined */
111  if ((pdset->common.number < 5) || (pdset->read_wf == NULL)) {
112  recGblRecordError(S_dev_missingSup,(void *)prec,"wf: init_record");
113  return S_dev_missingSup;
114  }
115  if (!pdset->common.init_record)
116  return 0;
117 
118  return pdset->common.init_record(pcommon);
119 }
120 
121 static long process(struct dbCommon *pcommon)
122 {
123  struct waveformRecord *prec = (struct waveformRecord *)pcommon;
124  wfdset *pdset = (wfdset *)(prec->dset);
125  unsigned char pact=prec->pact;
126  long status;
127 
128  if ((pdset==NULL) || (pdset->read_wf==NULL)) {
129  prec->pact=TRUE;
130  recGblRecordError(S_dev_missingSup, (void *)prec, "read_wf");
131  return S_dev_missingSup;
132  }
133 
134  if (pact && prec->busy)
135  return 0;
136 
137  status = readValue(prec); /* read the new value */
138  if (!pact && prec->pact)
139  return 0;
140 
141  prec->udf = FALSE;
142  recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
143 
144  monitor(prec);
145 
146  /* process the forward scan link record */
147  recGblFwdLink(prec);
148 
149  prec->pact=FALSE;
150  return status;
151 }
152 
153 static long special(DBADDR *paddr, int after)
154 {
155  waveformRecord *prec = (waveformRecord *)(paddr->precord);
156  int special_type = paddr->special;
157 
158  switch(special_type) {
159  case SPC_MOD:
160  if (dbGetFieldIndex(paddr) == waveformRecordSIMM) {
161  if (!after)
162  recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
163  else
164  recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm,
165  prec->simm);
166  return 0;
167  }
168  default:
169  recGblDbaddrError(S_db_badChoice, paddr, "waveform: special");
170  return S_db_badChoice;
171  }
172 }
173 
174 static long cvt_dbaddr(DBADDR *paddr)
175 {
176  waveformRecord *prec = (waveformRecord *) paddr->precord;
177 
178  paddr->no_elements = prec->nelm;
179  paddr->field_type = prec->ftvl;
180  paddr->field_size = dbValueSize(prec->ftvl);
181  paddr->dbr_field_type = prec->ftvl;
182 
183  return 0;
184 }
185 
186 static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
187 {
188  waveformRecord *prec = (waveformRecord *) paddr->precord;
189 
190  paddr->pfield = prec->bptr;
191  *no_elements = prec->nord;
192  *offset = 0;
193 
194  return 0;
195 }
196 
197 static long put_array_info(DBADDR *paddr, long nNew)
198 {
199  waveformRecord *prec = (waveformRecord *) paddr->precord;
200  epicsUInt32 nord = prec->nord;
201 
202  prec->nord = nNew;
203  if (prec->nord > prec->nelm)
204  prec->nord = prec->nelm;
205 
206  if (nord != prec->nord)
207  db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
208  return 0;
209 }
210 
211 #define indexof(field) waveformRecord##field
212 
213 static long get_units(DBADDR *paddr, char *units)
214 {
215  waveformRecord *prec = (waveformRecord *) paddr->precord;
216 
217  switch (dbGetFieldIndex(paddr)) {
218  case indexof(VAL):
219  if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM)
220  break;
221  case indexof(HOPR):
222  case indexof(LOPR):
223  strncpy(units,prec->egu,DB_UNITS_SIZE);
224  }
225  return 0;
226 }
227 
228 static long get_precision(const DBADDR *paddr, long *precision)
229 {
230  waveformRecord *prec = (waveformRecord *) paddr->precord;
231 
232  *precision = prec->prec;
233  if (dbGetFieldIndex(paddr) != indexof(VAL))
234  recGblGetPrec(paddr, precision);
235  return 0;
236 }
237 
238 static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
239 {
240  waveformRecord *prec = (waveformRecord *) paddr->precord;
241 
242  switch (dbGetFieldIndex(paddr)) {
243  case indexof(VAL):
244  pgd->upper_disp_limit = prec->hopr;
245  pgd->lower_disp_limit = prec->lopr;
246  break;
247  case indexof(BUSY):
248  pgd->upper_disp_limit = 1;
249  pgd->lower_disp_limit = 0;
250  break;
251  case indexof(NORD):
252  pgd->upper_disp_limit = prec->nelm;
253  pgd->lower_disp_limit = 0;
254  break;
255  default:
256  recGblGetGraphicDouble(paddr, pgd);
257  }
258  return 0;
259 }
260 
261 static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
262 {
263  waveformRecord *prec = (waveformRecord *) paddr->precord;
264 
265  switch (dbGetFieldIndex(paddr)) {
266  case indexof(VAL):
267  pcd->upper_ctrl_limit = prec->hopr;
268  pcd->lower_ctrl_limit = prec->lopr;
269  break;
270  case indexof(BUSY):
271  pcd->upper_ctrl_limit = 1;
272  pcd->lower_ctrl_limit = 0;
273  break;
274  case indexof(NORD):
275  pcd->upper_ctrl_limit = prec->nelm;
276  pcd->lower_ctrl_limit = 0;
277  break;
278  default:
279  recGblGetControlDouble(paddr, pcd);
280  }
281  return 0;
282 }
283 
284 static void monitor(waveformRecord *prec)
285 {
286  unsigned short monitor_mask = 0;
287  unsigned int hash = 0;
288 
289  monitor_mask = recGblResetAlarms(prec);
290 
291  if (prec->mpst == waveformPOST_Always)
292  monitor_mask |= DBE_VALUE;
293  if (prec->apst == waveformPOST_Always)
294  monitor_mask |= DBE_LOG;
295 
296  /* Calculate hash if we are interested in OnChange events. */
297  if ((prec->mpst == waveformPOST_OnChange) ||
298  (prec->apst == waveformPOST_OnChange)) {
299  hash = epicsMemHash((char *)prec->bptr,
300  prec->nord * dbValueSize(prec->ftvl), 0);
301 
302  /* Only post OnChange values if the hash is different. */
303  if (hash != prec->hash) {
304  if (prec->mpst == waveformPOST_OnChange)
305  monitor_mask |= DBE_VALUE;
306  if (prec->apst == waveformPOST_OnChange)
307  monitor_mask |= DBE_LOG;
308 
309  /* Store hash for next process. */
310  prec->hash = hash;
311  /* Post HASH. */
312  db_post_events(prec, &prec->hash, DBE_VALUE);
313  }
314  }
315 
316  if (monitor_mask) {
317  db_post_events(prec, &prec->val, monitor_mask);
318  }
319 }
320 
321 static long readValue(waveformRecord *prec)
322 {
323  wfdset *pdset = (wfdset *) prec->dset;
324  long status = 0;
325 
326  if (!prec->pact) {
327  status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm,
328  &prec->simm, &prec->siml);
329  if (status)
330  return status;
331  }
332 
333  switch (prec->simm) {
334  case menuYesNoNO: {
335  epicsUInt32 nord = prec->nord;
336 
337  status = pdset->read_wf(prec);
338  if (nord != prec->nord)
339  db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
340  break;
341  }
342 
343  case menuYesNoYES: {
344  long nRequest = prec->nelm;
345 
346  recGblSetSevr(prec, SIMM_ALARM, prec->sims);
347  if (prec->pact || (prec->sdly < 0)) {
348  status = dbGetLink(&prec->siol, prec->ftvl, prec->bptr, 0, &nRequest);
349  if (status == 0)
350  prec->udf = FALSE;
351 
352  if (nRequest != prec->nord) {
353  prec->nord = nRequest;
354  db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
355  }
356  prec->pact = FALSE;
357  }
358  else { /* !prec->pact && delay >= 0 */
359  epicsCallback *pvt = prec->simpvt;
360 
361  if (!pvt) { /* very lazy allocation of callback structure */
362  pvt = calloc(1, sizeof(epicsCallback));
363  prec->simpvt = pvt;
364  }
365  if (pvt)
366  callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec,
367  prec->sdly);
368  prec->pact = TRUE;
369  }
370  break;
371  }
372 
373  default:
374  recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
375  status = -1;
376  }
377 
378  return status;
379 }
#define RSETNUMBER
Definition: recSup.h:92
#define FALSE
Definition: dbDefs.h:32
epicsExportAddress(rset, waveformRSET)
pvd::Status status
#define get_enum_strs
#define init_record
#define S_dev_missingSup
Definition: devSup.h:170
#define SOFT_ALARM
Definition: alarm.h:106
#define NULL
Definition: catime.c:38
unsigned int epicsUInt32
Definition: epicsTypes.h:43
Miscellaneous macro definitions.
#define get_enum_str
#define get_control_double
Definition: biRecord.c:58
#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 get_units
Definition: biRecord.c:52
#define SIMM_ALARM
Definition: alarm.h:110
#define indexof(field)
#define get_value
LIBCOM_API void * callocMustSucceed(size_t count, size_t size, const char *msg)
A calloc() that never returns NULL.
Definition: cantProceed.c:22
#define get_precision
Definition: biRecord.c:53
#define put_array_info
Definition: aiRecord.c:57
#define report
#define initialize
#define TRUE
Definition: dbDefs.h:27
unsigned int epicsMemHash(const char *str, size_t length, unsigned int seed)
Definition: epicsString.c:369
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 INVALID_ALARM
Definition: alarm.h:53
rset waveformRSET
#define get_graphic_double
Definition: biRecord.c:57
#define cvt_dbaddr
Definition: aiRecord.c:55
#define put_enum_str
#define special
Definition: dfanoutRecord.c:50
#define S_dev_noDSET
Definition: devSup.h:169
#define get_alarm_double
Exporting IOC objects.