This is Unofficial EPICS BASE Doxygen Site
histogramRecord.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2012 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 /* histogramRecord.c - Record Support Routines for Histogram records */
11 /*
12  * Author: Janet Anderson
13  * Date: 5/20/91
14  */
15 
16 #include <stddef.h>
17 #include <stdlib.h>
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <math.h>
22 #include <limits.h>
23 
24 #include "dbDefs.h"
25 #include "epicsPrint.h"
26 #include "alarm.h"
27 #include "callback.h"
28 #include "dbAccess.h"
29 #include "dbEvent.h"
30 #include "epicsPrint.h"
31 #include "dbFldTypes.h"
32 #include "devSup.h"
33 #include "errMdef.h"
34 #include "special.h"
35 #include "recSup.h"
36 #include "recGbl.h"
37 #include "menuYesNo.h"
38 
39 #define GEN_SIZE_OFFSET
40 #include "histogramRecord.h"
41 #undef GEN_SIZE_OFFSET
42 #include "epicsExport.h"
43 
44 #define indexof(field) histogramRecord##field
45 
46 /* Create RSET - Record Support Entry Table*/
47 #define report NULL
48 #define initialize NULL
49 static long init_record(struct dbCommon *, int);
50 static long process(struct dbCommon *);
51 static long special(DBADDR *, int);
52 #define get_value NULL
53 static long cvt_dbaddr(DBADDR *);
54 static long get_array_info(DBADDR *, long *, long *);
55 #define put_array_info NULL
56 static long get_units(DBADDR *, char *);
57 static long get_precision(const DBADDR *paddr,long *precision);
58 #define get_enum_str NULL
59 #define get_enum_strs NULL
60 #define put_enum_str NULL
61 #define get_alarm_double NULL
62 static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd);
63 static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd);
64 
66  RSETNUMBER,
67  report,
68  initialize,
70  process,
71  special,
72  get_value,
73  cvt_dbaddr,
76  get_units,
84 };
85 epicsExportAddress(rset,histogramRSET);
86 
89 
90 /* control block for callback*/
91 typedef struct myCallback {
92  epicsCallback callback;
93  histogramRecord *prec;
94 } myCallback;
95 
96 static long add_count(histogramRecord *);
97 static long clear_histogram(histogramRecord *);
98 static void monitor(histogramRecord *);
99 static long readValue(histogramRecord *);
100 
101 
102 static void wdogCallback(epicsCallback *arg)
103 {
104  myCallback *pcallback;
105  histogramRecord *prec;
106 
107  callbackGetUser(pcallback, arg);
108  prec = pcallback->prec;
109  /* force post events for any count change */
110  if (prec->mcnt > 0){
111  dbScanLock((struct dbCommon *)prec);
112  recGblGetTimeStamp(prec);
113  db_post_events(prec, prec->bptr, DBE_VALUE | DBE_LOG);
114  prec->mcnt = 0;
115  dbScanUnlock((struct dbCommon *)prec);
116  }
117 
118  if (prec->sdel > 0) {
119  /* restart timer */
120  callbackRequestDelayed(&pcallback->callback, prec->sdel);
121  }
122 
123  return;
124 }
125 
126 static void wdogInit(histogramRecord *prec)
127 {
128  if (prec->sdel > 0) {
129  myCallback *pcallback = prec->wdog;
130 
131  if (!pcallback) {
132  /* initialize a callback object */
133  pcallback = calloc(1, sizeof(myCallback));
134  if (!pcallback)
135  return;
136 
137  pcallback->prec = prec;
138  callbackSetCallback(wdogCallback, &pcallback->callback);
139  callbackSetUser(pcallback, &pcallback->callback);
140  callbackSetPriority(priorityLow, &pcallback->callback);
141  prec->wdog = pcallback;
142  }
143 
144  /* start new timer on monitor */
145  callbackRequestDelayed(&pcallback->callback, prec->sdel);
146  }
147 }
148 
149 static long init_record(struct dbCommon *pcommon, int pass)
150 {
151  struct histogramRecord *prec = (struct histogramRecord *)pcommon;
152  histogramdset *pdset;
153 
154  if (pass == 0) {
155  /* allocate space for histogram array */
156  if (!prec->bptr) {
157  if (prec->nelm <= 0)
158  prec->nelm = 1;
159  prec->bptr = calloc(prec->nelm, sizeof(epicsUInt32));
160  }
161 
162  /* calulate width of array element */
163  prec->wdth = (prec->ulim - prec->llim) / prec->nelm;
164  return 0;
165  }
166 
167  wdogInit(prec);
168 
169  recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
170  recGblInitConstantLink(&prec->siol, DBF_DOUBLE, &prec->sval);
171 
172  /* must have device support defined */
173  pdset = (histogramdset *) prec->dset;
174  if (!pdset) {
175  recGblRecordError(S_dev_noDSET, prec, "histogram: init_record");
176  return S_dev_noDSET;
177  }
178 
179  /* must have read_histogram function defined */
180  if (pdset->common.number < 6 || !pdset->read_histogram) {
181  recGblRecordError(S_dev_missingSup, prec, "histogram: init_record");
182  return S_dev_missingSup;
183  }
184 
185  /* call device support init_record */
186  if (pdset->common.init_record) {
187  long status = pdset->common.init_record(pcommon);
188 
189  if (status)
190  return status;
191  }
192  return 0;
193 }
194 
195 static long process(struct dbCommon *pcommon)
196 {
197  struct histogramRecord *prec = (struct histogramRecord *)pcommon;
198  histogramdset *pdset = (histogramdset *) prec->dset;
199  int pact = prec->pact;
200  long status;
201 
202  if (!pdset || !pdset->read_histogram) {
203  prec->pact = TRUE;
204  recGblRecordError(S_dev_missingSup, prec, "read_histogram");
205  return S_dev_missingSup;
206  }
207 
208  status = readValue(prec); /* read the new value */
209 
210  /* check if device support set pact */
211  if (!pact && prec->pact)
212  return 0;
213  prec->pact = TRUE;
214 
215  recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
216 
217  if (status == 0)
218  add_count(prec);
219  else if (status == 2)
220  status = 0;
221 
222  monitor(prec);
223  recGblFwdLink(prec);
224 
225  prec->pact=FALSE;
226  return status;
227 }
228 
229 static long special(DBADDR *paddr, int after)
230 {
231  histogramRecord *prec = (histogramRecord *) paddr->precord;
232 
233  if (paddr->special == SPC_MOD && dbGetFieldIndex(paddr) == histogramRecordSIMM) {
234  if (!after)
235  recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
236  else
237  recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
238  return 0;
239  }
240 
241  if (!after)
242  return 0;
243 
244  switch (paddr->special) {
245  case SPC_CALC:
246  if (prec->cmd <= 1) {
247  clear_histogram(prec);
248  prec->cmd = 0;
249  }
250  else if (prec->cmd == 2) {
251  prec->csta = TRUE;
252  prec->cmd = 0;
253  }
254  else if (prec->cmd == 3) {
255  prec->csta = FALSE;
256  prec->cmd = 0;
257  }
258  return 0;
259 
260  case SPC_MOD:
261  /* increment frequency in histogram array */
262  add_count(prec);
263  return 0;
264 
265  case SPC_RESET:
266  if (dbGetFieldIndex(paddr) == histogramRecordSDEL) {
267  wdogInit(prec);
268  }
269  else {
270  prec->wdth = (prec->ulim - prec->llim) / prec->nelm;
271  clear_histogram(prec);
272  }
273  return 0;
274 
275  default:
276  recGblDbaddrError(S_db_badChoice, paddr, "histogram: special");
277  return S_db_badChoice;
278  }
279 }
280 
281 static void monitor(histogramRecord *prec)
282 {
283  unsigned short monitor_mask = recGblResetAlarms(prec);
284 
285  /* post events for count change */
286  if (prec->mcnt > prec->mdel){
287  monitor_mask |= DBE_VALUE | DBE_LOG;
288  /* reset counts since monitor */
289  prec->mcnt = 0;
290  }
291  /* send out monitors connected to the value field */
292  if (monitor_mask)
293  db_post_events(prec, prec->bptr, monitor_mask);
294 
295  return;
296 }
297 
298 static long cvt_dbaddr(DBADDR *paddr)
299 {
300  histogramRecord *prec = (histogramRecord *) paddr->precord;
301 
302  paddr->pfield = prec->bptr;
303  paddr->no_elements = prec->nelm;
304  paddr->field_type = DBF_ULONG;
305  paddr->field_size = sizeof(epicsUInt32);
306  paddr->dbr_field_type = DBF_ULONG;
307  return 0;
308 }
309 
310 static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
311 {
312  histogramRecord *prec = (histogramRecord *) paddr->precord;
313 
314  *no_elements = prec->nelm;
315  *offset = 0;
316  return 0;
317 }
318 
319 static long add_count(histogramRecord *prec)
320 {
321  double temp;
322  epicsUInt32 *pdest;
323  int i;
324 
325  if (prec->csta == FALSE)
326  return 0;
327 
328  if (prec->llim >= prec->ulim) {
329  if (prec->nsev < INVALID_ALARM) {
330  prec->stat = SOFT_ALARM;
331  prec->sevr = INVALID_ALARM;
332  return -1;
333  }
334  }
335  if (prec->sgnl < prec->llim ||
336  prec->sgnl >= prec->ulim)
337  return 0;
338 
339  temp = prec->sgnl - prec->llim;
340  for (i = 1; i <= prec->nelm; i++){
341  if (temp <= (double) i * prec->wdth)
342  break;
343  }
344  pdest = prec->bptr + i - 1;
345  if (*pdest == (epicsUInt32) UINT_MAX)
346  *pdest = 0;
347  (*pdest)++;
348  prec->mcnt++;
349 
350  return 0;
351 }
352 
353 static long clear_histogram(histogramRecord *prec)
354 {
355  int i;
356 
357  for (i = 0; i < prec->nelm; i++)
358  prec->bptr[i] = 0;
359  prec->mcnt = prec->mdel + 1;
360  prec->udf = FALSE;
361 
362  return 0;
363 }
364 
365 static long readValue(histogramRecord *prec)
366 {
367  histogramdset *pdset = (histogramdset *) prec->dset;
368  long status = 0;
369 
370  if (!prec->pact) {
371  status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
372  if (status) return status;
373  }
374 
375  switch (prec->simm) {
376  case menuYesNoNO:
377  status = pdset->read_histogram(prec);
378  break;
379 
380  case menuYesNoYES: {
381  recGblSetSevr(prec, SIMM_ALARM, prec->sims);
382  if (prec->pact || (prec->sdly < 0.)) {
383  status = dbGetLink(&prec->siol, DBR_DOUBLE, &prec->sval, 0, 0);
384  if (status == 0) {
385  prec->sgnl = prec->sval;
386  prec->udf = FALSE;
387  }
388  prec->pact = FALSE;
389  } else { /* !prec->pact && delay >= 0. */
390  epicsCallback *pvt = prec->simpvt;
391  if (!pvt) {
392  pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */
393  prec->simpvt = pvt;
394  }
395  if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
396  prec->pact = TRUE;
397  }
398  break;
399  }
400 
401  default:
402  recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
403  status = -1;
404  }
405 
406  return status;
407 }
408 
409 static long get_units(DBADDR *paddr, char *units)
410 {
411  if (dbGetFieldIndex(paddr) == indexof(SDEL)) {
412  strcpy(units,"s");
413  }
414  /* We should have EGU for other DOUBLE values or probably get it from input link SVL */
415  return 0;
416 }
417 
418 static long get_precision(const DBADDR *paddr,long *precision)
419 {
420  histogramRecord *prec = (histogramRecord *) paddr->precord;
421 
422  switch (dbGetFieldIndex(paddr)) {
423  case indexof(ULIM):
424  case indexof(LLIM):
425  case indexof(SGNL):
426  case indexof(SVAL):
427  case indexof(WDTH):
428  *precision = prec->prec;
429  break;
430  case indexof(SDEL):
431  *precision = histogramSDELprecision;
432  break;
433  default:
434  recGblGetPrec(paddr,precision);
435  }
436  return 0;
437 }
438 
439 static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd)
440 {
441  histogramRecord *prec = (histogramRecord *) paddr->precord;
442 
443  switch (dbGetFieldIndex(paddr)) {
444  case indexof(VAL):
445  pgd->upper_disp_limit = prec->hopr;
446  pgd->lower_disp_limit = prec->lopr;
447  break;
448  case indexof(WDTH):
449  pgd->upper_disp_limit = prec->ulim - prec->llim;
450  pgd->lower_disp_limit = 0.0;
451  break;
452  default:
453  recGblGetGraphicDouble(paddr,pgd);
454  }
455  return 0;
456 }
457 static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd)
458 {
459  histogramRecord *prec = (histogramRecord *) paddr->precord;
460 
461  switch (dbGetFieldIndex(paddr)) {
462  case indexof(VAL):
463  pcd->upper_ctrl_limit = prec->hopr;
464  pcd->lower_ctrl_limit = prec->lopr;
465  break;
466  case indexof(WDTH):
467  pcd->upper_ctrl_limit = prec->ulim - prec->llim;
468  pcd->lower_ctrl_limit = 0.0;
469  break;
470  default:
471  recGblGetControlDouble(paddr, pcd);
472  }
473  return 0;
474 }
#define RSETNUMBER
Definition: recSup.h:92
int histogramSDELprecision
#define get_enum_strs
#define FALSE
Definition: dbDefs.h:32
#define get_alarm_double
#define initialize
pvd::Status status
int i
Definition: scan.c:967
#define put_enum_str
#define init_record
#define SPC_CALC
Definition: special.h:39
#define S_dev_missingSup
Definition: devSup.h:170
struct myCallback myCallback
#define SOFT_ALARM
Definition: alarm.h:106
epicsCallback callback
Definition: boRecord.c:91
unsigned int epicsUInt32
Definition: epicsTypes.h:43
Miscellaneous macro definitions.
#define indexof(field)
#define get_control_double
Definition: biRecord.c:58
#define SPC_RESET
Definition: special.h:35
histogramRecord * prec
#define DBE_VALUE
Definition: caeventmask.h:38
#define get_array_info
Definition: aiRecord.c:56
epicsExportAddress(rset, histogramRSET)
#define get_enum_str
Device support routines.
#define put_array_info
#define DBE_LOG
Definition: caeventmask.h:40
#define get_units
Definition: biRecord.c:52
#define SIMM_ALARM
Definition: alarm.h:110
#define DBR_DOUBLE
Definition: db_access.h:76
#define get_value
#define report
#define get_precision
Definition: biRecord.c:53
#define TRUE
Definition: dbDefs.h:27
if(yy_init)
Definition: scan.c:972
Definition: recSup.h:67
#define SPC_MOD
Definition: special.h:33
rset histogramRSET
#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 S_dev_noDSET
Definition: devSup.h:169
Exporting IOC objects.