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