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