This is Unofficial EPICS BASE Doxygen Site
aaoRecord.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 /* recAao.c */
8 
9 /* recAao.c - Record Support Routines for Array Analog Out 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 "special.h"
44 #include "cantProceed.h"
45 #include "menuYesNo.h"
46 
47 #define GEN_SIZE_OFFSET
48 #include "aaoRecord.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,aaoRSET);
92 
93 static void monitor(aaoRecord *);
94 static long writeValue(aaoRecord *);
95 
96 static long init_record(struct dbCommon *pcommon, int pass)
97 {
98  struct aaoRecord *prec = (struct aaoRecord *)pcommon;
99  aaodset *pdset = (aaodset *)(prec->dset);
100  long status;
101 
102  /* must have dset defined */
103  if (!pdset) {
104  recGblRecordError(S_dev_noDSET, prec, "aao: init_record");
105  return S_dev_noDSET;
106  }
107 
108  if (pass == 0) {
109  if (prec->nelm <= 0)
110  prec->nelm = 1;
111  if (prec->ftvl > DBF_ENUM)
112  prec->ftvl = DBF_UCHAR;
113  if (prec->nelm == 1) {
114  prec->nord = 1;
115  } else {
116  prec->nord = 0;
117  }
118 
119  /* we must call pdset->init_record in pass 0
120  because it may set prec->bptr which must
121  not change after links are established before pass 1
122  */
123 
124  if (pdset->common.init_record) {
125  /* init_record may set the bptr to point to the data */
126  if ((status = pdset->common.init_record(pcommon)))
127  return status;
128  }
129  if (!prec->bptr) {
130  /* device support did not allocate memory so we must do it */
131  prec->bptr = callocMustSucceed(prec->nelm, dbValueSize(prec->ftvl),
132  "aao: buffer calloc failed");
133  }
134  return 0;
135  }
136 
137  recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
138 
139  /* must have write_aao function defined */
140  if (pdset->common.number < 5 || pdset->write_aao == NULL) {
141  recGblRecordError(S_dev_missingSup, prec, "aao: init_record");
142  return S_dev_missingSup;
143  }
144  return 0;
145 }
146 
147 static long process(struct dbCommon *pcommon)
148 {
149  struct aaoRecord *prec = (struct aaoRecord *)pcommon;
150  aaodset *pdset = (aaodset *)(prec->dset);
151  long status;
152  unsigned char pact = prec->pact;
153 
154  if (pdset == NULL || pdset->write_aao == NULL) {
155  prec->pact = TRUE;
156  recGblRecordError(S_dev_missingSup, prec, "write_aao");
157  return S_dev_missingSup;
158  }
159 
160  status = writeValue(prec); /* write the data */
161  if (!pact && prec->pact) return 0;
162  prec->pact = TRUE;
163 
164  prec->udf = FALSE;
165  recGblGetTimeStampSimm(prec, prec->simm, NULL);
166 
167  monitor(prec);
168  /* process the forward scan link record */
169  recGblFwdLink(prec);
170 
171  prec->pact = FALSE;
172  return status;
173 }
174 
175 static long special(DBADDR *paddr, int after)
176 {
177  aaoRecord *prec = (aaoRecord *)(paddr->precord);
178  int special_type = paddr->special;
179 
180  switch(special_type) {
181  case(SPC_MOD):
182  if (dbGetFieldIndex(paddr) == aaoRecordSIMM) {
183  if (!after)
184  recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
185  else
186  recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
187  return(0);
188  }
189  default:
190  recGblDbaddrError(S_db_badChoice, paddr, "aao: special");
191  return(S_db_badChoice);
192  }
193 }
194 
195 static long cvt_dbaddr(DBADDR *paddr)
196 {
197  aaoRecord *prec = (aaoRecord *)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  aaoRecord *prec = (aaoRecord *)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  aaoRecord *prec = (aaoRecord *)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) aaoRecord##field
231 
232 static long get_units(DBADDR *paddr, char *units)
233 {
234  aaoRecord *prec = (aaoRecord *)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  aaoRecord *prec = (aaoRecord *)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  aaoRecord *prec = (aaoRecord *)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  aaoRecord *prec = (aaoRecord *)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(aaoRecord *prec)
296 {
297  unsigned short monitor_mask;
298  unsigned int hash = 0;
299 
300  monitor_mask = recGblResetAlarms(prec);
301 
302  if (prec->mpst == aaoPOST_Always)
303  monitor_mask |= DBE_VALUE;
304  if (prec->apst == aaoPOST_Always)
305  monitor_mask |= DBE_LOG;
306 
307  /* Calculate hash if we are interested in OnChange events. */
308  if ((prec->mpst == aaoPOST_OnChange) ||
309  (prec->apst == aaoPOST_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 == aaoPOST_OnChange)
316  monitor_mask |= DBE_VALUE;
317  if (prec->apst == aaoPOST_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 writeValue(aaoRecord *prec)
332 {
333  aaodset *pdset = (aaodset *) prec->dset;
334  long status = 0;
335 
336  if (!prec->pact) {
337  status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
338  if (status) return status;
339  }
340 
341  switch (prec->simm) {
342  case menuYesNoNO:
343  status = pdset->write_aao(prec);
344  break;
345 
346  case menuYesNoYES: {
347  recGblSetSevr(prec, SIMM_ALARM, prec->sims);
348  if (prec->pact || (prec->sdly < 0.)) {
349  /* Device suport is responsible for buffer
350  which might be write-only so we may not be
351  allowed to call dbPutLink on it.
352  Maybe also device support has an advanced
353  simulation mode.
354  Thus call device now.
355 
356  Writing through SIOL is handled in Soft Channel Device Support
357  */
358  status = pdset->write_aao(prec);
359  prec->pact = FALSE;
360  } else { /* !prec->pact && delay >= 0. */
361  epicsCallback *pvt = prec->simpvt;
362  if (!pvt) {
363  pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */
364  prec->simpvt = pvt;
365  }
366  if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
367  prec->pact = TRUE;
368  }
369  break;
370  }
371 
372  default:
373  recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
374  status = -1;
375  }
376 
377  return status;
378 }
#define RSETNUMBER
Definition: recSup.h:92
#define get_alarm_double
Definition: aaoRecord.c:69
#define FALSE
Definition: dbDefs.h:32
pvd::Status status
#define indexof(field)
Definition: aaoRecord.c:230
#define init_record
#define S_dev_missingSup
Definition: devSup.h:170
#define get_enum_str
Definition: aaoRecord.c:64
#define report
Definition: aaoRecord.c:53
#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_control_double
Definition: biRecord.c:58
#define put_enum_str
Definition: aaoRecord.c:66
#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 initialize
Definition: aaoRecord.c:54
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
epicsExportAddress(rset, aaoRSET)
#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.
#define get_enum_strs
Definition: aaoRecord.c:65
int prec
Definition: reader.c:29
#define INVALID_ALARM
Definition: alarm.h:53
#define get_graphic_double
Definition: biRecord.c:57
rset aaoRSET
Definition: aaoRecord.c:71
#define cvt_dbaddr
Definition: aiRecord.c:55
#define special
Definition: dfanoutRecord.c:50
#define get_value
Definition: aaoRecord.c:58
#define S_dev_noDSET
Definition: devSup.h:169
Exporting IOC objects.