This is Unofficial EPICS BASE Doxygen Site
boRecord.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 /* recBo.c - Record Support Routines for Binary Output records */
11 /*
12  * Original Author: Bob Dalesio
13  * Date: 7-14-89
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 "errMdef.h"
31 #include "recSup.h"
32 #include "recGbl.h"
33 #include "special.h"
34 #include "menuIvoa.h"
35 #include "menuOmsl.h"
36 #include "menuYesNo.h"
37 
38 #define GEN_SIZE_OFFSET
39 #include "boRecord.h"
40 #undef GEN_SIZE_OFFSET
41 #include "epicsExport.h"
42 
43 /* Create RSET - Record Support Entry Table*/
44 #define report NULL
45 #define initialize NULL
46 static long init_record(struct dbCommon *, int);
47 static long process(struct dbCommon *);
48 static long special(DBADDR *, int);
49 #define get_value NULL
50 #define cvt_dbaddr NULL
51 #define get_array_info NULL
52 #define put_array_info NULL
53 static long get_units(DBADDR *, char *);
54 static long get_precision(const DBADDR *, long *);
55 static long get_enum_str(const DBADDR *, char *);
56 static long get_enum_strs(const DBADDR *, struct dbr_enumStrs *);
57 static long put_enum_str(const DBADDR *, const char *);
58 #define get_graphic_double NULL
59 static long get_control_double(DBADDR *, struct dbr_ctrlDouble *);
60 #define get_alarm_double NULL
61 
63  RSETNUMBER,
64  report,
65  initialize,
67  process,
68  special,
69  get_value,
70  cvt_dbaddr,
73  get_units,
81 };
82 epicsExportAddress(rset,boRSET);
83 
86 double boHIGHlimit = 100000;
88 
89 /* control block for callback*/
90 typedef struct myCallback {
91  epicsCallback callback;
92  struct dbCommon *precord;
93 }myCallback;
94 
95 static void checkAlarms(boRecord *);
96 static void monitor(boRecord *);
97 static long writeValue(boRecord *);
98 
99 static void myCallbackFunc(epicsCallback *arg)
100 {
101  myCallback *pcallback;
102  boRecord *prec;
103 
104  callbackGetUser(pcallback,arg);
105  prec=(boRecord *)pcallback->precord;
106  dbScanLock((struct dbCommon *)prec);
107  if(prec->pact) {
108  if((prec->val==1) && (prec->high>0)){
109  myCallback *pcallback;
110  pcallback = (myCallback *)(prec->rpvt);
111  callbackSetPriority(prec->prio, &pcallback->callback);
112  callbackRequestDelayed(&pcallback->callback,(double)prec->high);
113  }
114  } else {
115  prec->val = 0;
116  dbProcess((struct dbCommon *)prec);
117  }
118  dbScanUnlock((struct dbCommon *)prec);
119 }
120 
121 static long init_record(struct dbCommon *pcommon,int pass)
122 {
123  struct boRecord *prec = (struct boRecord *)pcommon;
124  bodset *pdset = (bodset *) prec->dset;
125  unsigned short ival = 0;
126  long status = 0;
127  myCallback *pcallback;
128 
129  if (pass == 0) return 0;
130 
131  recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
132 
133  if (!pdset) {
134  recGblRecordError(S_dev_noDSET, prec, "bo: init_record");
135  return S_dev_noDSET;
136  }
137 
138  /* must have write_bo functions defined */
139  if ((pdset->common.number < 5) || (pdset->write_bo == NULL)) {
140  recGblRecordError(S_dev_missingSup, prec, "bo: init_record");
141  return S_dev_missingSup;
142  }
143 
144  /* get the initial value */
145  if (recGblInitConstantLink(&prec->dol, DBF_USHORT, &ival)) {
146  prec->val = !!ival;
147  prec->udf = FALSE;
148  }
149 
150  pcallback = (myCallback *) calloc(1, sizeof(myCallback));
151  prec->rpvt = pcallback;
152  callbackSetCallback(myCallbackFunc, &pcallback->callback);
153  callbackSetUser(pcallback, &pcallback->callback);
154  pcallback->precord = (struct dbCommon *) prec;
155 
156  if (pdset->common.init_record) {
157  status=(*pdset->common.init_record)(pcommon);
158  if(status==0) {
159  if(prec->rval==0) prec->val = 0;
160  else prec->val = 1;
161  prec->udf = FALSE;
162  } else if (status==2) status=0;
163  }
164  prec->mlst = prec->val;
165  /* convert val to rval */
166  if ( prec->mask != 0 ) {
167  if(prec->val==0) prec->rval = 0;
168  else prec->rval = prec->mask;
169  } else prec->rval = (epicsUInt32)prec->val;
170 
171  prec->mlst = prec->val;
172  prec->lalm = prec->val;
173  prec->oraw = prec->rval;
174  prec->orbv = prec->rbv;
175  return(status);
176 }
177 
178 static long process(struct dbCommon *pcommon)
179 {
180  struct boRecord *prec = (struct boRecord *)pcommon;
181  bodset *pdset = (bodset *)(prec->dset);
182  long status=0;
183  unsigned char pact=prec->pact;
184 
185  if( (pdset==NULL) || (pdset->write_bo==NULL) ) {
186  prec->pact=TRUE;
187  recGblRecordError(S_dev_missingSup,(void *)prec,"write_bo");
188  return(S_dev_missingSup);
189  }
190  if (!prec->pact) {
191  if (!dbLinkIsConstant(&prec->dol) &&
192  prec->omsl == menuOmslclosed_loop) {
193  unsigned short val;
194 
195  prec->pact = TRUE;
196  status=dbGetLink(&prec->dol,DBR_USHORT, &val,0,0);
197  prec->pact = FALSE;
198  if(status==0){
199  prec->val = val;
200  prec->udf = FALSE;
201  }else {
202  recGblSetSevr(prec,LINK_ALARM,INVALID_ALARM);
203  }
204  }
205 
206  /* convert val to rval */
207  if ( prec->mask != 0 ) {
208  if(prec->val==0) prec->rval = 0;
209  else prec->rval = prec->mask;
210  } else prec->rval = (epicsUInt32)prec->val;
211  }
212 
213  /* check for alarms */
214  checkAlarms(prec);
215 
216  if (prec->nsev < INVALID_ALARM )
217  status=writeValue(prec); /* write the new value */
218  else {
219  switch (prec->ivoa) {
220  case (menuIvoaContinue_normally) :
221  status=writeValue(prec); /* write the new value */
222  break;
223  case (menuIvoaDon_t_drive_outputs) :
224  break;
225  case (menuIvoaSet_output_to_IVOV) :
226  if(prec->pact == FALSE){
227  /* convert val to rval */
228  prec->val=prec->ivov;
229  if ( prec->mask != 0 ) {
230  if(prec->val==0) prec->rval = 0;
231  else prec->rval = prec->mask;
232  } else prec->rval = (epicsUInt32)prec->val;
233  }
234  status=writeValue(prec); /* write the new value */
235  break;
236  default :
237  status=-1;
238  recGblRecordError(S_db_badField,(void *)prec,
239  "bo:process Illegal IVOA field");
240  }
241  }
242 
243  /* check if device support set pact */
244  if ( !pact && prec->pact ) return(0);
245  prec->pact = TRUE;
246 
247  recGblGetTimeStampSimm(prec, prec->simm, NULL);
248 
249  if((prec->val==1) && (prec->high>0)){
250  myCallback *pcallback;
251  pcallback = (myCallback *)(prec->rpvt);
252  callbackSetPriority(prec->prio, &pcallback->callback);
253  callbackRequestDelayed(&pcallback->callback,(double)prec->high);
254  }
255  /* check event list */
256  monitor(prec);
257  /* process the forward scan link record */
258  recGblFwdLink(prec);
259 
260  prec->pact=FALSE;
261  return(status);
262 }
263 
264 static long special(DBADDR *paddr, int after)
265 {
266  boRecord *prec = (boRecord *)(paddr->precord);
267  int special_type = paddr->special;
268 
269  switch(special_type) {
270  case(SPC_MOD):
271  if (dbGetFieldIndex(paddr) == boRecordSIMM) {
272  if (!after)
273  recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
274  else
275  recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
276  return(0);
277  }
278  default:
279  recGblDbaddrError(S_db_badChoice, paddr, "bo: special");
280  return(S_db_badChoice);
281  }
282 }
283 
284 #define indexof(field) boRecord##field
285 
286 static long get_units(DBADDR *paddr, char *units)
287 {
288  if(dbGetFieldIndex(paddr) == indexof(HIGH))
289  strcpy(units, "s");
290  return(0);
291 }
292 
293 static long get_precision(const DBADDR *paddr, long *precision)
294 {
295  if(dbGetFieldIndex(paddr) == indexof(HIGH))
296  *precision = boHIGHprecision;
297  else
298  recGblGetPrec(paddr,precision);
299  return(0);
300 }
301 
302 static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd)
303 {
304  if(dbGetFieldIndex(paddr) == indexof(HIGH)) {
305  pcd->lower_ctrl_limit = 0.0;
306  pcd->upper_ctrl_limit = boHIGHlimit;
307  } else
308  recGblGetControlDouble(paddr,pcd);
309  return(0);
310 }
311 
312 static long get_enum_str(const DBADDR *paddr, char *pstring)
313 {
314  boRecord *prec=(boRecord *)paddr->precord;
315  int index;
316  unsigned short *pfield = (unsigned short *)paddr->pfield;
317 
318 
319  index = dbGetFieldIndex(paddr);
320  if(index!=indexof(VAL)) {
321  strcpy(pstring,"Illegal_Value");
322  } else if(*pfield==0) {
323  strncpy(pstring,prec->znam,sizeof(prec->znam));
324  pstring[sizeof(prec->znam)] = 0;
325  } else if(*pfield==1) {
326  strncpy(pstring,prec->onam,sizeof(prec->onam));
327  pstring[sizeof(prec->onam)] = 0;
328  } else {
329  strcpy(pstring,"Illegal_Value");
330  }
331  return(0);
332 }
333 
334 static long get_enum_strs(const DBADDR *paddr,struct dbr_enumStrs *pes)
335 {
336  boRecord *prec=(boRecord *)paddr->precord;
337 
338  /*SETTING no_str=0 breaks channel access clients*/
339  pes->no_str = 2;
340  memset(pes->strs,'\0',sizeof(pes->strs));
341  strncpy(pes->strs[0],prec->znam,sizeof(pes->strs[0]));
342  if(*prec->znam!=0) pes->no_str=1;
343  strncpy(pes->strs[1],prec->onam,sizeof(pes->strs[1]));
344  if(*prec->onam!=0) pes->no_str=2;
345  return(0);
346 }
347 static long put_enum_str(const DBADDR *paddr, const char *pstring)
348 {
349  boRecord *prec=(boRecord *)paddr->precord;
350 
351  if(strncmp(pstring,prec->znam,sizeof(prec->znam))==0) prec->val = 0;
352  else if(strncmp(pstring,prec->onam,sizeof(prec->onam))==0) prec->val = 1;
353  else return(S_db_badChoice);
354  return(0);
355 }
356 
357 
358 static void checkAlarms(boRecord *prec)
359 {
360  unsigned short val = prec->val;
361 
362  /* check for udf alarm */
363  if(prec->udf == TRUE ){
364  recGblSetSevr(prec,UDF_ALARM,prec->udfs);
365  }
366 
367  /* check for state alarm */
368  if (val == 0){
369  recGblSetSevr(prec,STATE_ALARM,prec->zsv);
370  }else{
371  recGblSetSevr(prec,STATE_ALARM,prec->osv);
372  }
373 
374  /* check for cos alarm */
375  if(val == prec->lalm) return;
376  recGblSetSevr(prec,COS_ALARM,prec->cosv);
377  prec->lalm = val;
378  return;
379 }
380 
381 static void monitor(boRecord *prec)
382 {
383  unsigned short monitor_mask;
384 
385  monitor_mask = recGblResetAlarms(prec);
386  /* check for value change */
387  if (prec->mlst != prec->val){
388  /* post events for value change and archive change */
389  monitor_mask |= (DBE_VALUE | DBE_LOG);
390  /* update last value monitored */
391  prec->mlst = prec->val;
392  }
393 
394  /* send out monitors connected to the value field */
395  if (monitor_mask){
396  db_post_events(prec,&prec->val,monitor_mask);
397  }
398  if(prec->oraw!=prec->rval) {
399  db_post_events(prec,&prec->rval,
400  monitor_mask|DBE_VALUE|DBE_LOG);
401  prec->oraw = prec->rval;
402  }
403  if(prec->orbv!=prec->rbv) {
404  db_post_events(prec,&prec->rbv,
405  monitor_mask|DBE_VALUE|DBE_LOG);
406  prec->orbv = prec->rbv;
407  }
408  return;
409 }
410 
411 static long writeValue(boRecord *prec)
412 {
413  bodset *pdset = (bodset *) prec->dset;
414  long status = 0;
415 
416  if (!prec->pact) {
417  status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
418  if (status) return status;
419  }
420 
421  switch (prec->simm) {
422  case menuYesNoNO:
423  status = pdset->write_bo(prec);
424  break;
425 
426  case menuYesNoYES: {
427  recGblSetSevr(prec, SIMM_ALARM, prec->sims);
428  if (prec->pact || (prec->sdly < 0.)) {
429  status = dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
430  prec->pact = FALSE;
431  } else { /* !prec->pact && delay >= 0. */
432  epicsCallback *pvt = prec->simpvt;
433  if (!pvt) {
434  pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */
435  prec->simpvt = pvt;
436  }
437  if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
438  prec->pact = TRUE;
439  }
440  break;
441  }
442 
443  default:
444  recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
445  status = -1;
446  }
447 
448  return status;
449 }
#define put_array_info
Definition: boRecord.c:52
#define get_graphic_double
Definition: boRecord.c:58
#define RSETNUMBER
Definition: recSup.h:92
#define cvt_dbaddr
Definition: boRecord.c:50
#define get_alarm_double
Definition: boRecord.c:60
#define FALSE
Definition: dbDefs.h:32
int boHIGHprecision
Definition: boRecord.c:84
pvd::Status status
#define get_enum_strs
Definition: aaiRecord.c:65
#define DBR_USHORT
Definition: dbFldTypes.h:80
#define indexof(field)
Definition: boRecord.c:284
#define init_record
#define S_dev_missingSup
Definition: devSup.h:170
#define SOFT_ALARM
Definition: alarm.h:106
#define NULL
Definition: catime.c:38
epicsCallback callback
Definition: boRecord.c:91
unsigned int epicsUInt32
Definition: epicsTypes.h:43
Miscellaneous macro definitions.
#define get_value
Definition: boRecord.c:49
#define get_control_double
Definition: biRecord.c:58
#define COS_ALARM
Definition: alarm.h:99
histogramRecord * prec
#define DBE_VALUE
Definition: caeventmask.h:38
#define initialize
Definition: boRecord.c:45
double boHIGHlimit
Definition: boRecord.c:86
Device support routines.
#define DBE_LOG
Definition: caeventmask.h:40
epicsExportAddress(rset, boRSET)
#define get_units
Definition: biRecord.c:52
#define SIMM_ALARM
Definition: alarm.h:110
rset boRSET
Definition: boRecord.c:62
#define get_array_info
Definition: boRecord.c:51
#define LINK_ALARM
Definition: alarm.h:105
struct myCallback myCallback
#define put_enum_str
Definition: aaiRecord.c:66
#define get_precision
Definition: biRecord.c:53
#define TRUE
Definition: dbDefs.h:27
#define report
Definition: boRecord.c:44
if(yy_init)
Definition: scan.c:972
Definition: recSup.h:67
#define SPC_MOD
Definition: special.h:33
#define STATE_ALARM
Definition: alarm.h:98
struct dbCommon * precord
Definition: boRecord.c:92
#define INVALID_ALARM
Definition: alarm.h:53
#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.