This is Unofficial EPICS BASE Doxygen Site
mbboRecord.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 /* mbboRecord.c - Record Support Routines for multi bit binary Output records */
12 /*
13  * Original Author: Bob Dalesio
14  * Date: 7-17-87
15  */
16 
17 #include <stddef.h>
18 #include <stdlib.h>
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <string.h>
22 
23 #include "dbDefs.h"
24 #include "epicsPrint.h"
25 #include "alarm.h"
26 #include "callback.h"
27 #include "dbAccess.h"
28 #include "dbEvent.h"
29 #include "dbFldTypes.h"
30 #include "devSup.h"
31 #include "errMdef.h"
32 #include "recSup.h"
33 #include "recGbl.h"
34 #include "special.h"
35 #include "menuOmsl.h"
36 #include "menuIvoa.h"
37 #include "menuYesNo.h"
38 
39 #define GEN_SIZE_OFFSET
40 #include "mbboRecord.h"
41 #undef GEN_SIZE_OFFSET
42 #include "epicsExport.h"
43 
44 /* Create RSET - Record Support Entry Table*/
45 #define report NULL
46 #define initialize NULL
47 static long init_record(struct dbCommon *, int);
48 static long process(struct dbCommon *);
49 static long special(DBADDR *, int);
50 #define get_value NULL
51 static long cvt_dbaddr(DBADDR *);
52 #define get_array_info NULL
53 #define put_array_info NULL
54 #define get_units NULL
55 #define get_precision NULL
56 static long get_enum_str(const DBADDR *, char *);
57 static long get_enum_strs(const DBADDR *, struct dbr_enumStrs *);
58 static long put_enum_str(const DBADDR *, const char *);
59 #define get_graphic_double NULL
60 #define get_control_double NULL
61 #define get_alarm_double NULL
62 
64  RSETNUMBER,
65  report,
66  initialize,
68  process,
69  special,
70  get_value,
71  cvt_dbaddr,
74  get_units,
82 };
83 epicsExportAddress(rset,mbboRSET);
84 
85 
86 static void checkAlarms(mbboRecord *);
87 static void convert(mbboRecord *);
88 static void monitor(mbboRecord *);
89 static long writeValue(mbboRecord *);
90 
91 
92 static void init_common(mbboRecord *prec)
93 {
94  epicsUInt32 *pstate_values = &prec->zrvl;
95  char *pstate_string = prec->zrst;
96  int i;
97 
98  /* Check if any states are defined */
99  for (i = 0; i < 16; i++, pstate_string += sizeof(prec->zrst)) {
100  if ((pstate_values[i] != 0) || (*pstate_string != '\0')) {
101  prec->sdef = TRUE;
102  return;
103  }
104  }
105  prec->sdef = FALSE;
106 }
107 
108 static long init_record(struct dbCommon *pcommon, int pass)
109 {
110  struct mbboRecord *prec = (struct mbboRecord *)pcommon;
111  mbbodset *pdset;
112  long status;
113 
114  if (pass == 0) {
115  init_common(prec);
116  return 0;
117  }
118 
119  pdset = (mbbodset *) prec->dset;
120  if (!pdset) {
121  recGblRecordError(S_dev_noDSET, prec, "mbbo: init_record");
122  return S_dev_noDSET;
123  }
124 
125  if ((pdset->common.number < 5) || (pdset->write_mbbo == NULL)) {
126  recGblRecordError(S_dev_missingSup, prec, "mbbo: init_record");
127  return S_dev_missingSup;
128  }
129 
130  recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
131 
132  if (recGblInitConstantLink(&prec->dol, DBF_USHORT, &prec->val))
133  prec->udf = FALSE;
134 
135  /* Initialize MASK if the user set NOBT instead */
136  if (prec->mask == 0 && prec->nobt <= 32)
137  prec->mask = ((epicsUInt64) 1u << prec->nobt) - 1;
138 
139  if (pdset->common.init_record) {
140  status = pdset->common.init_record(pcommon);
141  init_common(prec);
142  if (status == 0) {
143  /* Convert initial read-back */
144  epicsUInt32 rval = prec->rval;
145 
146  if (prec->shft > 0)
147  rval >>= prec->shft;
148 
149  if (prec->sdef) {
150  epicsUInt32 *pstate_values = &prec->zrvl;
151  int i;
152 
153  prec->val = 65535; /* initalize to unknown state */
154  for (i = 0; i < 16; i++) {
155  if (*pstate_values == rval) {
156  prec->val = i;
157  break;
158  }
159  pstate_values++;
160  }
161  }
162  else {
163  /* No defined states, punt */
164  prec->val = rval;
165  }
166  prec->udf = FALSE;
167  }
168  else if (status == 2)
169  status = 0;
170  }
171  else {
172  init_common(prec);
173  status = 0;
174  }
175  /* Convert VAL to RVAL */
176  convert(prec);
177 
178  prec->mlst = prec->val;
179  prec->lalm = prec->val;
180  prec->oraw = prec->rval;
181  prec->orbv = prec->rbv;
182  return status;
183 }
184 
185 static long process(struct dbCommon *pcommon)
186 {
187  struct mbboRecord *prec = (struct mbboRecord *)pcommon;
188  mbbodset *pdset = (mbbodset *) prec->dset;
189  long status = 0;
190  int pact = prec->pact;
191 
192  if ((pdset == NULL) || (pdset->write_mbbo == NULL)) {
193  prec->pact = TRUE;
194  recGblRecordError(S_dev_missingSup, prec, "write_mbbo");
195  return S_dev_missingSup;
196  }
197 
198  if (!pact) {
199  if (!dbLinkIsConstant(&prec->dol) &&
200  prec->omsl == menuOmslclosed_loop) {
201  epicsUInt16 val;
202 
203  if (dbGetLink(&prec->dol, DBR_USHORT, &val, 0, 0)) {
204  recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
205  goto CONTINUE;
206  }
207  prec->val = val;
208  }
209  else if (prec->udf) {
210  recGblSetSevr(prec, UDF_ALARM, prec->udfs);
211  goto CONTINUE;
212  }
213 
214  prec->udf = FALSE;
215  /* Convert VAL to RVAL */
216  convert(prec);
217  }
218 
219 CONTINUE:
220  /* Check for alarms */
221  checkAlarms(prec);
222 
223  if (prec->nsev < INVALID_ALARM)
224  status = writeValue(prec);
225  else {
226  switch (prec->ivoa) {
227  case menuIvoaSet_output_to_IVOV:
228  if (!prec->pact) {
229  prec->val = prec->ivov;
230  convert(prec);
231  }
232  /* No break, fall through... */
233  case menuIvoaContinue_normally:
234  status = writeValue(prec);
235  break;
236  case menuIvoaDon_t_drive_outputs:
237  break;
238  default :
239  status = -1;
240  recGblRecordError(S_db_badField, prec,
241  "mbbo::process Illegal IVOA field");
242  }
243  }
244 
245  /* Done if device support set pact */
246  if (!pact && prec->pact)
247  return 0;
248 
249  prec->pact = TRUE;
250  recGblGetTimeStampSimm(prec, prec->simm, NULL);
251 
252  monitor(prec);
253 
254  /* Wrap up */
255  recGblFwdLink(prec);
256  prec->pact = FALSE;
257  return status;
258 }
259 
260 static long special(DBADDR *paddr, int after)
261 {
262  mbboRecord *prec = (mbboRecord *) paddr->precord;
263  int fieldIndex = dbGetFieldIndex(paddr);
264 
265  switch (paddr->special) {
266  case SPC_MOD:
267  if (fieldIndex == mbboRecordSIMM) {
268  if (!after)
269  recGblSaveSimm(prec->sscn, &prec->oldsimm, prec->simm);
270  else
271  recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
272  return 0;
273  }
274 
275  if (!after)
276  return 0;
277  init_common(prec);
278  /* Note: ZRVL..FFVL are also SPC_MOD */
279  if (fieldIndex >= mbboRecordZRST && fieldIndex <= mbboRecordFFST) {
280  int event = DBE_PROPERTY;
281 
282  if (prec->val == fieldIndex - mbboRecordZRST)
283  event |= DBE_VALUE | DBE_LOG;
284  db_post_events(prec, &prec->val, event);
285  }
286  return 0;
287 
288  default:
289  recGblDbaddrError(S_db_badChoice, paddr, "mbbo: special");
290  return S_db_badChoice;
291  }
292 }
293 
294 static long cvt_dbaddr(DBADDR *paddr)
295 {
296  mbboRecord *prec = (mbboRecord *) paddr->precord;
297 
298  if (dbGetFieldIndex(paddr) != mbboRecordVAL) {
299  recGblDbaddrError(S_db_badField, paddr, "mbbo: cvt_dbaddr");
300  return 0;
301  }
302  if (!prec->sdef) {
303  paddr->field_type = DBF_USHORT;
304  paddr->dbr_field_type = DBF_USHORT;
305  }
306  return 0;
307 }
308 
309 static long get_enum_str(const DBADDR *paddr, char *pstring)
310 {
311  mbboRecord *prec = (mbboRecord *) paddr->precord;
312  epicsEnum16 *pfield = paddr->pfield;
313  epicsEnum16 val = *pfield;
314 
315  if (dbGetFieldIndex(paddr) != mbboRecordVAL) {
316  strcpy(pstring, "Bad Field");
317  }
318  else if (val <= 15) {
319  const char *pstate = prec->zrst + val * sizeof(prec->zrst);
320 
321  strncpy(pstring, pstate, sizeof(prec->zrst));
322  }
323  else {
324  strcpy(pstring, "Illegal Value");
325  }
326  return 0;
327 }
328 
329 static long get_enum_strs(const DBADDR *paddr, struct dbr_enumStrs *pes)
330 {
331  mbboRecord *prec = (mbboRecord *) paddr->precord;
332  const char *pstate;
333  int i, states = 0;
334 
335  memset(pes->strs, '\0', sizeof(pes->strs));
336  pstate = prec->zrst;
337  for (i = 0; i < 16; i++) {
338  strncpy(pes->strs[i], pstate, sizeof(prec->zrst));
339  if (*pstate)
340  states = i + 1;
341  pstate += sizeof(prec->zrst);
342  }
343  pes->no_str = states;
344 
345  return 0;
346 }
347 
348 static long put_enum_str(const DBADDR *paddr, const char *pstring)
349 {
350  mbboRecord *prec = (mbboRecord *) paddr->precord;
351  const char *pstate;
352  int i;
353 
354  if (prec->sdef) {
355  pstate = prec->zrst;
356  for (i = 0; i < 16; i++) {
357  if (strncmp(pstate, pstring, sizeof(prec->zrst)) == 0) {
358  prec->val = i;
359  return 0;
360  }
361  pstate += sizeof(prec->zrst);
362  }
363  }
364  return S_db_badChoice;
365 }
366 
367 static void checkAlarms(mbboRecord *prec)
368 {
369  epicsEnum16 val = prec->val;
370 
371  /* Check for STATE alarm */
372  if (val > 15) {
373  /* Unknown state */
374  recGblSetSevr(prec, STATE_ALARM, prec->unsv);
375  }
376  else {
377  /* State has a severity field */
378  epicsEnum16 *severities = &prec->zrsv;
379  recGblSetSevr(prec, STATE_ALARM, severities[prec->val]);
380  }
381 
382  /* Check for COS alarm */
383  if (val == prec->lalm ||
384  recGblSetSevr(prec, COS_ALARM, prec->cosv))
385  return;
386 
387  prec->lalm = val;
388 }
389 
390 static void monitor(mbboRecord *prec)
391 {
392  epicsUInt16 events = recGblResetAlarms(prec);
393 
394  if (prec->mlst != prec->val) {
395  events |= DBE_VALUE | DBE_LOG;
396  prec->mlst = prec->val;
397  }
398  if (events)
399  db_post_events(prec, &prec->val, events);
400 
401  events |= DBE_VALUE | DBE_LOG;
402  if (prec->oraw != prec->rval) {
403  db_post_events(prec, &prec->rval, events);
404  prec->oraw = prec->rval;
405  }
406  if (prec->orbv != prec->rbv) {
407  db_post_events(prec, &prec->rbv, events);
408  prec->orbv = prec->rbv;
409  }
410 }
411 
412 static void convert(mbboRecord *prec)
413 {
414  /* Convert VAL to RVAL */
415  if (prec->sdef) {
416  epicsUInt32 *pvalues = &prec->zrvl;
417 
418  if (prec->val > 15) {
419  recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
420  return;
421  }
422  prec->rval = pvalues[prec->val];
423  }
424  else
425  prec->rval = prec->val;
426 
427  if (prec->shft > 0)
428  prec->rval <<= prec->shft;
429 }
430 
431 static long writeValue(mbboRecord *prec)
432 {
433  mbbodset *pdset = (mbbodset *) prec->dset;
434  long status = 0;
435 
436  if (!prec->pact) {
437  status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
438  if (status) return status;
439  }
440 
441  switch (prec->simm) {
442  case menuYesNoNO:
443  status = pdset->write_mbbo(prec);
444  break;
445 
446  case menuYesNoYES: {
447  recGblSetSevr(prec, SIMM_ALARM, prec->sims);
448  if (prec->pact || (prec->sdly < 0.)) {
449  status = dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
450  prec->pact = FALSE;
451  } else { /* !prec->pact && delay >= 0. */
452  epicsCallback *pvt = prec->simpvt;
453  if (!pvt) {
454  pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */
455  prec->simpvt = pvt;
456  }
457  if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
458  prec->pact = TRUE;
459  }
460  break;
461  }
462 
463  default:
464  recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
465  status = -1;
466  }
467 
468  return status;
469 }
#define RSETNUMBER
Definition: recSup.h:92
#define FALSE
Definition: dbDefs.h:32
pvd::Status status
int i
Definition: scan.c:967
#define get_enum_strs
Definition: aaiRecord.c:65
#define DBR_USHORT
Definition: dbFldTypes.h:80
unsigned short epicsUInt16
Definition: epicsTypes.h:41
#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
#define get_graphic_double
Definition: mbboRecord.c:59
Miscellaneous macro definitions.
unsigned long long epicsUInt64
Definition: epicsTypes.h:45
#define COS_ALARM
Definition: alarm.h:99
epicsExportAddress(rset, mbboRSET)
#define DBE_VALUE
Definition: caeventmask.h:38
#define put_array_info
Definition: mbboRecord.c:53
Device support routines.
#define DBE_LOG
Definition: caeventmask.h:40
#define SIMM_ALARM
Definition: alarm.h:110
#define get_control_double
Definition: mbboRecord.c:60
#define LINK_ALARM
Definition: alarm.h:105
#define get_alarm_double
Definition: mbboRecord.c:61
#define get_array_info
Definition: mbboRecord.c:52
#define DBE_PROPERTY
Definition: caeventmask.h:42
epicsUInt16 epicsEnum16
Definition: epicsTypes.h:47
#define put_enum_str
Definition: aaiRecord.c:66
#define TRUE
Definition: dbDefs.h:27
if(yy_init)
Definition: scan.c:972
Definition: recSup.h:67
#define report
Definition: mbboRecord.c:45
#define SPC_MOD
Definition: special.h:33
#define STATE_ALARM
Definition: alarm.h:98
#define initialize
Definition: mbboRecord.c:46
int prec
Definition: reader.c:29
rset mbboRSET
Definition: mbboRecord.c:63
#define INVALID_ALARM
Definition: alarm.h:53
#define cvt_dbaddr
Definition: aiRecord.c:55
#define get_value
Definition: mbboRecord.c:50
#define get_units
Definition: mbboRecord.c:54
#define special
Definition: dfanoutRecord.c:50
#define get_enum_str
Definition: aaiRecord.c:64
#define get_precision
Definition: mbboRecord.c:55
#define S_dev_noDSET
Definition: devSup.h:169
#define UDF_ALARM
Definition: alarm.h:108
Exporting IOC objects.