This is Unofficial EPICS BASE Doxygen Site
mbbiRecord.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2009 Helmholtz-Zentrum Berlin fuer Materialien und Energie.
3 * Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
4 * National Laboratory.
5 * Copyright (c) 2002 The Regents of the University of California, as
6 * Operator of Los Alamos National Laboratory.
7 * EPICS BASE is distributed subject to a Software License Agreement found
8 * in file LICENSE that is included with this distribution.
9 \*************************************************************************/
10 
11 /*
12  * Original Author: Bob Dalesio
13  * Date: 5-9-88
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 "alarm.h"
25 #include "callback.h"
26 #include "dbAccess.h"
27 #include "dbEvent.h"
28 #include "dbFldTypes.h"
29 #include "devSup.h"
30 #include "epicsMath.h"
31 #include "errMdef.h"
32 #include "menuSimm.h"
33 #include "recSup.h"
34 #include "recGbl.h"
35 #include "special.h"
36 
37 #define GEN_SIZE_OFFSET
38 #include "mbbiRecord.h"
39 #undef GEN_SIZE_OFFSET
40 #include "epicsExport.h"
41 
42 /* Hysterisis for alarm filtering: 1-1/e */
43 #define THRESHOLD 0.6321
44 
45 /* Create RSET - Record Support Entry Table*/
46 #define report NULL
47 #define initialize NULL
48 static long init_record(struct dbCommon *, int);
49 static long process(struct dbCommon *);
50 static long special(DBADDR *, int);
51 #define get_value NULL
52 #define cvt_dbaddr NULL
53 #define get_array_info NULL
54 #define put_array_info NULL
55 #define get_units NULL
56 #define get_precision NULL
57 static long get_enum_str(const DBADDR *, char *);
58 static long get_enum_strs(const DBADDR *, struct dbr_enumStrs *);
59 static long put_enum_str(const DBADDR *, const char *);
60 #define get_graphic_double NULL
61 #define get_control_double NULL
62 #define get_alarm_double NULL
63 
65  RSETNUMBER,
66  report,
67  initialize,
69  process,
70  special,
71  get_value,
72  cvt_dbaddr,
75  get_units,
83 };
84 epicsExportAddress(rset,mbbiRSET);
85 
86 static void checkAlarms(mbbiRecord *, epicsTimeStamp *);
87 static void monitor(mbbiRecord *);
88 static long readValue(mbbiRecord *);
89 
90 static void init_common(mbbiRecord *prec)
91 {
92  epicsUInt32 *pstate_values = &prec->zrvl;
93  char *pstate_string = prec->zrst;
94  int i;
95 
96  /* Check if any states are defined */
97  for (i = 0; i < 16; i++, pstate_string += sizeof(prec->zrst)) {
98  if ((pstate_values[i] != 0) || (*pstate_string != '\0')) {
99  prec->sdef = TRUE;
100  return;
101  }
102  }
103  prec->sdef = FALSE;
104 }
105 
106 static long init_record(struct dbCommon *pcommon, int pass)
107 {
108  struct mbbiRecord *prec = (struct mbbiRecord *)pcommon;
109  mbbidset *pdset = (mbbidset *) prec->dset;
110  long status = 0;
111 
112  if (pass == 0) return 0;
113 
114  if (!pdset) {
115  recGblRecordError(S_dev_noDSET, prec, "mbbi: init_record");
116  return S_dev_noDSET;
117  }
118 
119  if ((pdset->common.number < 5) || (pdset->read_mbbi == NULL)) {
120  recGblRecordError(S_dev_missingSup, prec, "mbbi: init_record");
121  return S_dev_missingSup;
122  }
123 
124  recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
125  recGblInitConstantLink(&prec->siol, DBF_USHORT, &prec->sval);
126 
127  /* Initialize MASK if the user set NOBT instead */
128  if (prec->mask == 0 && prec->nobt <= 32)
129  prec->mask = ((epicsUInt64) 1u << prec->nobt) - 1;
130 
131  if (pdset->common.init_record)
132  status = pdset->common.init_record(pcommon);
133 
134  init_common(prec);
135 
136  prec->mlst = prec->val;
137  prec->lalm = prec->val;
138  prec->oraw = prec->rval;
139  return status;
140 }
141 
142 static long process(struct dbCommon *pcommon)
143 {
144  struct mbbiRecord *prec = (struct mbbiRecord *)pcommon;
145  mbbidset *pdset = (mbbidset *) prec->dset;
146  long status;
147  int pact = prec->pact;
148  epicsTimeStamp timeLast;
149 
150  if ((pdset == NULL) || (pdset->read_mbbi == NULL)) {
151  prec->pact = TRUE;
152  recGblRecordError(S_dev_missingSup, prec, "read_mbbi");
153  return S_dev_missingSup;
154  }
155 
156  timeLast = prec->time;
157 
158  status = readValue(prec);
159 
160  /* Done if device support set PACT */
161  if (!pact && prec->pact)
162  return 0;
163 
164  prec->pact = TRUE;
165  recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
166 
167  if (status == 0) {
168  /* Convert RVAL to VAL */
169  epicsUInt32 *pstate_values;
170  short i;
171  epicsUInt32 rval = prec->rval;
172 
173  prec->udf = FALSE;
174  if (prec->shft > 0)
175  rval >>= prec->shft;
176 
177  if (prec->sdef) {
178  pstate_values = &(prec->zrvl);
179  prec->val = 65535; /* Initalize to unknown state*/
180  for (i = 0; i < 16; i++) {
181  if (*pstate_values == rval) {
182  prec->val = i;
183  break;
184  }
185  pstate_values++;
186  }
187  }
188  else /* No states defined, set VAL = RVAL */
189  prec->val = rval;
190  }
191  else if (status == 2)
192  status = 0;
193 
194  checkAlarms(prec, &timeLast);
195  monitor(prec);
196 
197  /* Wrap up */
198  recGblFwdLink(prec);
199  prec->pact=FALSE;
200  return status;
201 }
202 
203 static long special(DBADDR *paddr, int after)
204 {
205  mbbiRecord *prec = (mbbiRecord *) paddr->precord;
206  int fieldIndex = dbGetFieldIndex(paddr);
207 
208  switch (paddr->special) {
209  case SPC_MOD:
210  if (fieldIndex == mbbiRecordSIMM) {
211  if (!after)
212  recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
213  else
214  recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
215  return 0;
216  }
217 
218  if (!after)
219  return 0;
220  init_common(prec);
221  /* Note: ZRVL..FFVL are also SPC_MOD */
222  if (fieldIndex >= mbbiRecordZRST && fieldIndex <= mbbiRecordFFST) {
223  int event = DBE_PROPERTY;
224 
225  if (prec->val == fieldIndex - mbbiRecordZRST)
226  event |= DBE_VALUE | DBE_LOG;
227  db_post_events(prec, &prec->val, event);
228  }
229  return 0;
230 
231  default:
232  recGblDbaddrError(S_db_badChoice, paddr, "mbbi: special");
233  return S_db_badChoice;
234  }
235 }
236 
237 static long get_enum_str(const DBADDR *paddr, char *pstring)
238 {
239  mbbiRecord *prec = (mbbiRecord *) paddr->precord;
240  int index;
241  unsigned short *pfield = paddr->pfield;
242  epicsEnum16 val = *pfield;
243 
244  index = dbGetFieldIndex(paddr);
245  if (index != mbbiRecordVAL) {
246  strcpy(pstring, "Illegal_Value");
247  }
248  else if (val <= 15) {
249  char *pstate = prec->zrst + val * sizeof(prec->zrst);
250 
251  strncpy(pstring, pstate, sizeof(prec->zrst));
252  }
253  else {
254  strcpy(pstring, "Illegal Value");
255  }
256  return 0;
257 }
258 
259 static long get_enum_strs(const DBADDR *paddr, struct dbr_enumStrs *pes)
260 {
261  mbbiRecord *prec = (mbbiRecord *) paddr->precord;
262  char *pstate = prec->zrst;
263  int i;
264  short states = 0;
265 
266  memset(pes->strs, '\0', sizeof(pes->strs));
267  for (i = 0; i < 16; i++, pstate += sizeof(prec->zrst) ) {
268  strncpy(pes->strs[i], pstate, sizeof(prec->zrst));
269  if (*pstate!=0) states = i+1;
270  }
271  pes->no_str = states;
272  return 0;
273 }
274 
275 static long put_enum_str(const DBADDR *paddr, const char *pstring)
276 {
277  mbbiRecord *prec = (mbbiRecord *) paddr->precord;
278  char *pstate;
279  short i;
280 
281  if (prec->sdef) {
282  pstate = prec->zrst;
283  for (i = 0; i < 16; i++) {
284  if (strncmp(pstate, pstring, sizeof(prec->zrst)) == 0) {
285  prec->val = i;
286  prec->udf = FALSE;
287  return 0;
288  }
289  pstate += sizeof(prec->zrst);
290  }
291  }
292  return S_db_badChoice;
293 }
294 
295 static void checkAlarms(mbbiRecord *prec, epicsTimeStamp *timeLast)
296 {
297  double aftc, afvl;
298  unsigned short alarm;
299  epicsEnum16 asev;
300  epicsEnum16 val = prec->val;
301 
302  /* Check for UDF alarm */
303  if (prec->udf) {
304  recGblSetSevr(prec, UDF_ALARM, prec->udfs);
305  prec->afvl = 0;
306  return;
307  }
308 
309  /* Check for STATE alarm */
310  if (val > 15) {
311  /* Unknown state */
312  alarm = prec->unsv;
313  }
314  else {
315  /* State has a severity field */
316  epicsEnum16 *severities = &prec->zrsv;
317 
318  alarm = severities[prec->val];
319  }
320 
321  aftc = prec->aftc;
322  afvl = 0;
323 
324  if (aftc > 0) {
325  afvl = prec->afvl;
326  if (afvl == 0) {
327  afvl = (double) alarm;
328  }
329  else {
330  double t = epicsTimeDiffInSeconds(&prec->time, timeLast);
331  double alpha = aftc / (t + aftc);
332 
333  afvl = alpha * afvl +
334  ((afvl > 0) ? (1.0 - alpha) : (alpha - 1.0)) * alarm;
335  if (afvl - floor(afvl) > THRESHOLD)
336  afvl = -afvl;
337 
338  alarm = abs((int)floor(afvl));
339  }
340  }
341 
342  asev = alarm;
343  recGblSetSevr(prec, STATE_ALARM, asev);
344 
345  /* Check for COS alarm */
346  if (val == prec->lalm ||
347  recGblSetSevr(prec, COS_ALARM, prec->cosv))
348  return;
349 
350  prec->lalm = val;
351 }
352 
353 static void monitor(mbbiRecord *prec)
354 {
355  epicsUInt16 events = recGblResetAlarms(prec);
356 
357  if (prec->mlst != prec->val) {
358  events |= DBE_VALUE | DBE_LOG;
359  prec->mlst = prec->val;
360  }
361 
362  if (events)
363  db_post_events(prec, &prec->val, events);
364 
365  if (prec->oraw != prec->rval) {
366  db_post_events(prec, &prec->rval, events | DBE_VALUE | DBE_LOG);
367  prec->oraw = prec->rval;
368  }
369 }
370 
371 static long readValue(mbbiRecord *prec)
372 {
373  mbbidset *pdset = (mbbidset *) prec->dset;
374  long status = 0;
375 
376  if (!prec->pact) {
377  status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
378  if (status) return status;
379  }
380 
381  switch (prec->simm) {
382  case menuSimmNO:
383  status = pdset->read_mbbi(prec);
384  break;
385 
386  case menuSimmYES:
387  case menuSimmRAW: {
388  recGblSetSevr(prec, SIMM_ALARM, prec->sims);
389  if (prec->pact || (prec->sdly < 0.)) {
390  status = dbGetLink(&prec->siol, DBR_ULONG, &prec->sval, 0, 0);
391  if (status == 0) {
392  if (prec->simm == menuSimmYES) {
393  prec->val = prec->sval;
394  status = 2; /* Don't convert */
395  } else {
396  prec->rval = prec->sval;
397  }
398  prec->udf = FALSE;
399  }
400  prec->pact = FALSE;
401  } else { /* !prec->pact && delay >= 0. */
402  epicsCallback *pvt = prec->simpvt;
403  if (!pvt) {
404  pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */
405  prec->simpvt = pvt;
406  }
407  if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
408  prec->pact = TRUE;
409  }
410  break;
411  }
412 
413  default:
414  recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
415  status = -1;
416  }
417 
418  return status;
419 }
#define RSETNUMBER
Definition: recSup.h:92
#define FALSE
Definition: dbDefs.h:32
#define report
Definition: mbbiRecord.c:46
pvd::Status status
int i
Definition: scan.c:967
#define get_enum_strs
Definition: aaiRecord.c:65
#define put_array_info
Definition: mbbiRecord.c:54
epicsExportAddress(rset, mbbiRSET)
unsigned short epicsUInt16
Definition: epicsTypes.h:41
#define THRESHOLD
Definition: mbbiRecord.c:43
#define init_record
#define get_units
Definition: mbbiRecord.c:55
#define get_value
Definition: mbbiRecord.c:51
#define S_dev_missingSup
Definition: devSup.h:170
#define get_graphic_double
Definition: mbbiRecord.c:60
#define get_precision
Definition: mbbiRecord.c:56
#define SOFT_ALARM
Definition: alarm.h:106
#define NULL
Definition: catime.c:38
unsigned int epicsUInt32
Definition: epicsTypes.h:43
Miscellaneous macro definitions.
unsigned long long epicsUInt64
Definition: epicsTypes.h:45
#define COS_ALARM
Definition: alarm.h:99
#define DBE_VALUE
Definition: caeventmask.h:38
Device support routines.
rset mbbiRSET
Definition: mbbiRecord.c:64
#define DBE_LOG
Definition: caeventmask.h:40
#define get_control_double
Definition: mbbiRecord.c:61
#define SIMM_ALARM
Definition: alarm.h:110
#define get_alarm_double
Definition: mbbiRecord.c:62
#define get_array_info
Definition: mbbiRecord.c:53
#define initialize
Definition: mbbiRecord.c:47
#define DBE_PROPERTY
Definition: caeventmask.h:42
epicsUInt16 epicsEnum16
Definition: epicsTypes.h:47
#define put_enum_str
Definition: aaiRecord.c:66
#define cvt_dbaddr
Definition: mbbiRecord.c:52
EPICS time stamp, for use from C code.
Definition: epicsTime.h:33
#define TRUE
Definition: dbDefs.h:27
if(yy_init)
Definition: scan.c:972
Definition: recSup.h:67
LIBCOM_API double epicsStdCall epicsTimeDiffInSeconds(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
Time difference between left and right in seconds.
Definition: epicsTime.cpp:1048
#define SPC_MOD
Definition: special.h:33
#define STATE_ALARM
Definition: alarm.h:98
int prec
Definition: reader.c:29
#define INVALID_ALARM
Definition: alarm.h:53
#define DBR_ULONG
Definition: dbFldTypes.h:82
#define special
Definition: dfanoutRecord.c:50
#define get_enum_str
Definition: aaiRecord.c:64
#define S_dev_noDSET
Definition: devSup.h:169
#define UDF_ALARM
Definition: alarm.h:108
Exporting IOC objects.