This is Unofficial EPICS BASE Doxygen Site
longoutRecord.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2008 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 /*
11  * Author: Janet Anderson
12  * Date: 9/23/91
13  */
14 #include <stddef.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <stdio.h>
18 #include <string.h>
19 
20 #include "dbDefs.h"
21 #include "epicsPrint.h"
22 #include "epicsMath.h"
23 #include "alarm.h"
24 #include "callback.h"
25 #include "dbAccess.h"
26 #include "dbEvent.h"
27 #include "dbFldTypes.h"
28 #include "devSup.h"
29 #include "errMdef.h"
30 #include "recSup.h"
31 #include "recGbl.h"
32 #include "special.h"
33 #include "menuYesNo.h"
34 #include "menuIvoa.h"
35 #include "menuOmsl.h"
36 
37 #define GEN_SIZE_OFFSET
38 #include "longoutRecord.h"
39 #undef GEN_SIZE_OFFSET
40 #include "epicsExport.h"
41 
42 /* Create RSET - Record Support Entry Table*/
43 #define report NULL
44 #define initialize NULL
45 static long init_record(struct dbCommon *, int);
46 static long process(struct dbCommon *);
47 static long special(DBADDR *, int);
48 #define get_value NULL
49 #define cvt_dbaddr NULL
50 #define get_array_info NULL
51 #define put_array_info NULL
52 static long get_units(DBADDR *, char *);
53 #define get_precision NULL
54 #define get_enum_str NULL
55 #define get_enum_strs NULL
56 #define put_enum_str NULL
57 static long get_graphic_double(DBADDR *, struct dbr_grDouble *);
58 static long get_control_double(DBADDR *, struct dbr_ctrlDouble *);
59 static long get_alarm_double(DBADDR *, struct dbr_alDouble *);
60 
62  RSETNUMBER,
63  report,
64  initialize,
66  process,
67  special,
68  get_value,
69  cvt_dbaddr,
72  get_units,
80 };
81 epicsExportAddress(rset,longoutRSET);
82 
83 static void checkAlarms(longoutRecord *prec);
84 static void monitor(longoutRecord *prec);
85 static long writeValue(longoutRecord *prec);
86 static void convert(longoutRecord *prec, epicsInt32 value);
87 
88 static long init_record(struct dbCommon *pcommon, int pass)
89 {
90  struct longoutRecord *prec = (struct longoutRecord *)pcommon;
91  longoutdset *pdset = (longoutdset *) prec->dset;
92 
93  if (pass == 0) return 0;
94 
95  recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
96 
97  if (!pdset) {
98  recGblRecordError(S_dev_noDSET, prec, "longout: init_record");
99  return S_dev_noDSET;
100  }
101 
102  /* must have write_longout functions defined */
103  if ((pdset->common.number < 5) || (pdset->write_longout == NULL)) {
104  recGblRecordError(S_dev_missingSup, prec, "longout: init_record");
105  return S_dev_missingSup;
106  }
107 
108  if (recGblInitConstantLink(&prec->dol, DBF_LONG, &prec->val))
109  prec->udf=FALSE;
110 
111  if (pdset->common.init_record) {
112  long status = pdset->common.init_record(pcommon);
113 
114  if (status)
115  return status;
116  }
117 
118  prec->mlst = prec->val;
119  prec->alst = prec->val;
120  prec->lalm = prec->val;
121  return 0;
122 }
123 
124 static long process(struct dbCommon *pcommon)
125 {
126  struct longoutRecord *prec = (struct longoutRecord *)pcommon;
127  longoutdset *pdset = (longoutdset *)(prec->dset);
128  long status=0;
130  unsigned char pact=prec->pact;
131 
132  if( (pdset==NULL) || (pdset->write_longout==NULL) ) {
133  prec->pact=TRUE;
134  recGblRecordError(S_dev_missingSup,(void *)prec,"write_longout");
135  return(S_dev_missingSup);
136  }
137  if (!prec->pact) {
138  if (!dbLinkIsConstant(&prec->dol) &&
139  prec->omsl == menuOmslclosed_loop) {
140  status = dbGetLink(&prec->dol, DBR_LONG, &value, 0, 0);
141  if (!dbLinkIsConstant(&prec->dol) && !status)
142  prec->udf=FALSE;
143  }
144  else {
145  value = prec->val;
146  }
147  if (!status) convert(prec,value);
148  }
149 
150  /* check for alarms */
151  checkAlarms(prec);
152 
153  if (prec->nsev < INVALID_ALARM )
154  status=writeValue(prec); /* write the new value */
155  else {
156  switch (prec->ivoa) {
157  case (menuIvoaContinue_normally) :
158  status=writeValue(prec); /* write the new value */
159  break;
160  case (menuIvoaDon_t_drive_outputs) :
161  break;
162  case (menuIvoaSet_output_to_IVOV) :
163  if(prec->pact == FALSE){
164  prec->val=prec->ivov;
165  }
166  status=writeValue(prec); /* write the new value */
167  break;
168  default :
169  status=-1;
170  recGblRecordError(S_db_badField,(void *)prec,
171  "longout:process Illegal IVOA field");
172  }
173  }
174 
175  /* check if device support set pact */
176  if ( !pact && prec->pact ) return(0);
177  prec->pact = TRUE;
178 
179  recGblGetTimeStampSimm(prec, prec->simm, NULL);
180 
181  /* check event list */
182  monitor(prec);
183 
184  /* process the forward scan link record */
185  recGblFwdLink(prec);
186 
187  prec->pact=FALSE;
188  return(status);
189 }
190 
191 static long special(DBADDR *paddr, int after)
192 {
193  longoutRecord *prec = (longoutRecord *)(paddr->precord);
194  int special_type = paddr->special;
195 
196  switch(special_type) {
197  case(SPC_MOD):
198  if (dbGetFieldIndex(paddr) == longoutRecordSIMM) {
199  if (!after)
200  recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
201  else
202  recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
203  return(0);
204  }
205  default:
206  recGblDbaddrError(S_db_badChoice, paddr, "longout: special");
207  return(S_db_badChoice);
208  }
209 }
210 
211 #define indexof(field) longoutRecord##field
212 
213 static long get_units(DBADDR *paddr,char *units)
214 {
215  longoutRecord *prec=(longoutRecord *)paddr->precord;
216 
217  if(paddr->pfldDes->field_type == DBF_LONG) {
218  strncpy(units,prec->egu,DB_UNITS_SIZE);
219  }
220  return(0);
221 }
222 
223 static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd)
224 {
225  longoutRecord *prec=(longoutRecord *)paddr->precord;
226 
227  switch (dbGetFieldIndex(paddr)) {
228  case indexof(VAL):
229  case indexof(HIHI):
230  case indexof(HIGH):
231  case indexof(LOW):
232  case indexof(LOLO):
233  case indexof(LALM):
234  case indexof(ALST):
235  case indexof(MLST):
236  pgd->upper_disp_limit = prec->hopr;
237  pgd->lower_disp_limit = prec->lopr;
238  break;
239  default:
240  recGblGetGraphicDouble(paddr,pgd);
241  }
242  return(0);
243 }
244 
245 static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd)
246 {
247  longoutRecord *prec=(longoutRecord *)paddr->precord;
248 
249  switch (dbGetFieldIndex(paddr)) {
250  case indexof(VAL):
251  case indexof(HIHI):
252  case indexof(HIGH):
253  case indexof(LOW):
254  case indexof(LOLO):
255  case indexof(LALM):
256  case indexof(ALST):
257  case indexof(MLST):
258  /* do not change pre drvh/drvl behavior */
259  if(prec->drvh > prec->drvl) {
260  pcd->upper_ctrl_limit = prec->drvh;
261  pcd->lower_ctrl_limit = prec->drvl;
262  } else {
263  pcd->upper_ctrl_limit = prec->hopr;
264  pcd->lower_ctrl_limit = prec->lopr;
265  }
266  break;
267  default:
268  recGblGetControlDouble(paddr,pcd);
269  }
270  return(0);
271 }
272 
273 static long get_alarm_double(DBADDR *paddr,struct dbr_alDouble *pad)
274 {
275  longoutRecord *prec=(longoutRecord *)paddr->precord;
276 
277  if (dbGetFieldIndex(paddr) == indexof(VAL)) {
278  pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
279  pad->upper_warning_limit = prec->hsv ? prec->high : epicsNAN;
280  pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;
281  pad->lower_alarm_limit = prec->llsv ? prec->lolo : epicsNAN;
282  }
283  else
284  recGblGetAlarmDouble(paddr,pad);
285  return 0;
286 }
287 
288 static void checkAlarms(longoutRecord *prec)
289 {
290  epicsInt32 val, hyst, lalm;
291  epicsInt32 alev;
292  epicsEnum16 asev;
293 
294  if (prec->udf) {
295  recGblSetSevr(prec, UDF_ALARM, prec->udfs);
296  return;
297  }
298 
299  val = prec->val;
300  hyst = prec->hyst;
301  lalm = prec->lalm;
302 
303  /* alarm condition hihi */
304  asev = prec->hhsv;
305  alev = prec->hihi;
306  if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
307  if (recGblSetSevr(prec, HIHI_ALARM, asev))
308  prec->lalm = alev;
309  return;
310  }
311 
312  /* alarm condition lolo */
313  asev = prec->llsv;
314  alev = prec->lolo;
315  if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
316  if (recGblSetSevr(prec, LOLO_ALARM, asev))
317  prec->lalm = alev;
318  return;
319  }
320 
321  /* alarm condition high */
322  asev = prec->hsv;
323  alev = prec->high;
324  if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
325  if (recGblSetSevr(prec, HIGH_ALARM, asev))
326  prec->lalm = alev;
327  return;
328  }
329 
330  /* alarm condition low */
331  asev = prec->lsv;
332  alev = prec->low;
333  if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
334  if (recGblSetSevr(prec, LOW_ALARM, asev))
335  prec->lalm = alev;
336  return;
337  }
338 
339  /* we get here only if val is out of alarm by at least hyst */
340  prec->lalm = val;
341  return;
342 }
343 
344 /* DELTA calculates the absolute difference between its arguments
345  * expressed as an unsigned 32-bit integer */
346 #define DELTA(last, val) \
347  ((epicsUInt32) ((last) > (val) ? (last) - (val) : (val) - (last)))
348 
349 static void monitor(longoutRecord *prec)
350 {
351  unsigned short monitor_mask = recGblResetAlarms(prec);
352 
353  if (prec->mdel < 0 ||
354  DELTA(prec->mlst, prec->val) > (epicsUInt32) prec->mdel) {
355  /* post events for value change */
356  monitor_mask |= DBE_VALUE;
357  /* update last value monitored */
358  prec->mlst = prec->val;
359  }
360 
361  if (prec->adel < 0 ||
362  DELTA(prec->alst, prec->val) > (epicsUInt32) prec->adel) {
363  /* post events for archive value change */
364  monitor_mask |= DBE_LOG;
365  /* update last archive value monitored */
366  prec->alst = prec->val;
367  }
368 
369  /* send out monitors connected to the value field */
370  if (monitor_mask)
371  db_post_events(prec, &prec->val, monitor_mask);
372 }
373 
374 static long writeValue(longoutRecord *prec)
375 {
376  longoutdset *pdset = (longoutdset *) prec->dset;
377  long status = 0;
378 
379  if (!prec->pact) {
380  status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
381  if (status) return status;
382  }
383 
384  switch (prec->simm) {
385  case menuYesNoNO:
386  status = pdset->write_longout(prec);
387  break;
388 
389  case menuYesNoYES: {
390  recGblSetSevr(prec, SIMM_ALARM, prec->sims);
391  if (prec->pact || (prec->sdly < 0.)) {
392  status = dbPutLink(&prec->siol, DBR_LONG, &prec->val, 1);
393  prec->pact = FALSE;
394  } else { /* !prec->pact && delay >= 0. */
395  epicsCallback *pvt = prec->simpvt;
396  if (!pvt) {
397  pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */
398  prec->simpvt = pvt;
399  }
400  if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
401  prec->pact = TRUE;
402  }
403  break;
404  }
405 
406  default:
407  recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
408  status = -1;
409  }
410 
411  return status;
412 }
413 
414 static void convert(longoutRecord *prec, epicsInt32 value)
415 {
416  /* check drive limits */
417  if(prec->drvh > prec->drvl) {
418  if (value > prec->drvh) value = prec->drvh;
419  else if (value < prec->drvl) value = prec->drvl;
420  }
421  prec->val = value;
422 }
#define initialize
Definition: longoutRecord.c:44
#define HIHI_ALARM
Definition: alarm.h:94
#define RSETNUMBER
Definition: recSup.h:92
Definition: link.h:174
#define report
Definition: longoutRecord.c:43
#define FALSE
Definition: dbDefs.h:32
pvd::Status status
#define put_array_info
Definition: longoutRecord.c:51
#define cvt_dbaddr
Definition: longoutRecord.c:49
#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_control_double
Definition: biRecord.c:58
#define put_enum_str
Definition: longoutRecord.c:56
#define DBE_VALUE
Definition: caeventmask.h:38
#define HIGH_ALARM
Definition: alarm.h:95
Device support routines.
#define indexof(field)
#define DBE_LOG
Definition: caeventmask.h:40
#define get_units
Definition: biRecord.c:52
#define SIMM_ALARM
Definition: alarm.h:110
float epicsNAN
Definition: epicsMath.cpp:35
#define get_enum_strs
Definition: longoutRecord.c:55
#define DELTA(last, val)
epicsUInt16 epicsEnum16
Definition: epicsTypes.h:47
#define get_array_info
Definition: longoutRecord.c:50
#define DBR_LONG
Definition: db_access.h:75
#define get_precision
Definition: longoutRecord.c:53
rset longoutRSET
Definition: longoutRecord.c:61
#define TRUE
Definition: dbDefs.h:27
epicsExportAddress(rset, longoutRSET)
if(yy_init)
Definition: scan.c:972
Definition: recSup.h:67
#define SPC_MOD
Definition: special.h:33
#define get_value
Definition: longoutRecord.c:48
int prec
Definition: reader.c:29
#define INVALID_ALARM
Definition: alarm.h:53
#define LOLO_ALARM
Definition: alarm.h:96
#define LOW_ALARM
Definition: alarm.h:97
#define get_graphic_double
Definition: biRecord.c:57
#define special
Definition: dfanoutRecord.c:50
#define get_enum_str
Definition: longoutRecord.c:54
int epicsInt32
Definition: epicsTypes.h:42
#define S_dev_noDSET
Definition: devSup.h:169
#define get_alarm_double
Definition: aaiRecord.c:69
#define UDF_ALARM
Definition: alarm.h:108
Exporting IOC objects.