This is Unofficial EPICS BASE Doxygen Site
dbdToPv.cpp
Go to the documentation of this file.
1 
8 #include <epicsVersion.h>
9 #include <sstream>
10 #include <alarm.h>
11 #include <alarmString.h>
12 
13 #include <pv/alarm.h>
14 #include <pv/standardField.h>
15 #include <pv/logger.h>
16 #include <pv/pvAccess.h>
17 #include <pv/reftrack.h>
18 #include <pv/convert.h>
19 #include <pv/timeStamp.h>
20 #include "caChannel.h"
21 #define epicsExportSharedSymbols
22 #include "dbdToPv.h"
23 
24 using namespace epics::pvData;
25 using std::string;
26 using std::ostringstream;
27 using std::cout;
28 
29 namespace epics {
30 namespace pvAccess {
31 namespace ca {
32 
33 #define CA_PRIORITY 50
34 
35 
36 
37 DbdToPvPtr DbdToPv::create(
38  CAChannelPtr const & caChannel,
39  PVStructurePtr const & pvRequest,
40  IOType ioType)
41 {
42  DbdToPvPtr dbdToPv(new DbdToPv(ioType));
43  dbdToPv->activate(caChannel,pvRequest);
44  return dbdToPv;
45 }
46 
47 DbdToPv::DbdToPv(IOType ioType)
48 : ioType(ioType),
49  dbfIsUCHAR(false),
50  dbfIsUSHORT(false),
51  dbfIsULONG(false),
52  dbfIsINT64(false),
53  dbfIsUINT64(false),
54  valueRequested(false),
55  alarmRequested(false),
56  timeStampRequested(false),
57  displayRequested(false),
58  controlRequested(false),
59  valueAlarmRequested(false),
60  isArray(false),
61  charArrayIsString(false),
62  firstTime(true),
63  caValueType(-1),
64  caRequestType(-1),
65  maxElements(0)
66 {
67  caTimeStamp.secPastEpoch = 0;
68  caTimeStamp.nsec = 0;
69 }
70 
71 static ScalarType dbr2ST[] =
72 {
73  pvString, // DBR_STRING = 0
74  pvShort, // DBR_SHORT. DBR_INT = 1
75  pvFloat, // DBR_FLOAT = 2
76  static_cast<ScalarType>(-1), // DBR_ENUM = 3
77  pvByte, // DBR_CHAR = 4
78  pvInt, // DBR_LONG = 5
79  pvDouble // DBR_DOUBLE = 6
80 };
81 
82 static chtype getDbrType(const ScalarType scalarType)
83 {
84  switch(scalarType)
85  {
86  case pvString : return DBR_STRING;
87  case pvByte : return DBR_CHAR;
88  case pvUByte : return DBR_CHAR;
89  case pvShort : return DBR_SHORT;
90  case pvUShort : return DBR_SHORT;
91  case pvInt : return DBR_LONG;
92  case pvUInt : return DBR_LONG;
93  case pvFloat : return DBR_FLOAT;
94  case pvDouble : return DBR_DOUBLE;
95  case pvLong : return DBR_DOUBLE;
96  case pvULong : return DBR_DOUBLE;
97  default: break;
98  }
99  throw std::runtime_error("getDbr: illegal scalarType");
100 }
101 
102 static dbr_short_t convertDBstatus(dbr_short_t dbStatus)
103 {
104  switch(dbStatus) {
105  case NO_ALARM:
106  return noStatus;
107  case READ_ALARM:
108  case WRITE_ALARM:
109  case HIHI_ALARM:
110  case HIGH_ALARM:
111  case LOLO_ALARM:
112  case LOW_ALARM:
113  case STATE_ALARM:
114  case COS_ALARM:
115  case HW_LIMIT_ALARM:
116  return deviceStatus;
117  case COMM_ALARM:
118  case TIMEOUT_ALARM:
119  return driverStatus;
120  case CALC_ALARM:
121  case SCAN_ALARM:
122  case LINK_ALARM:
123  case SOFT_ALARM:
124  case BAD_SUB_ALARM:
125  return recordStatus;
126  case DISABLE_ALARM:
127  case SIMM_ALARM:
128  case READ_ACCESS_ALARM:
129  case WRITE_ACCESS_ALARM:
130  return dbStatus;
131  case UDF_ALARM:
132  return undefinedStatus;
133  default:
134  return undefinedStatus; // UNDEFINED
135  }
136 
137 }
138 
139 void DbdToPv::activate(
140  CAChannelPtr const & caChannel,
141  PVStructurePtr const & pvRequest)
142 {
143  chid channelID = caChannel->getChannelID();
144  chtype channelType = ca_field_type(channelID);
145  caValueType = (channelType==DBR_ENUM ? DBR_ENUM : getDbrType(dbr2ST[channelType]));
146  if(!pvRequest) {
147  string mess(caChannel->getChannelName());
148  mess += " DbdToPv::activate pvRequest is null";
149  throw std::runtime_error(mess);
150  }
151  PVStructurePtr fieldPVStructure;
152  if(pvRequest->getPVFields().size()==0) {
153  fieldPVStructure = pvRequest;
154  } else {
155  fieldPVStructure = pvRequest->getSubField<PVStructure>("field");
156  }
157  if(!fieldPVStructure) {
158  ostringstream mess;
159  mess << caChannel->getChannelName()
160  << " DbdToPv::activate illegal pvRequest " << pvRequest;
161  throw std::runtime_error(mess.str());
162  }
163  if(fieldPVStructure->getPVFields().size()==0)
164  {
165  valueRequested = true;
166  alarmRequested = true;
167  timeStampRequested = true;
168  displayRequested = true;
169  controlRequested = true;
170  valueAlarmRequested = true;
171  } else {
172  if(fieldPVStructure->getSubField("value")) valueRequested = true;
173  if(fieldPVStructure->getSubField("alarm")) alarmRequested = true;
174  if(fieldPVStructure->getSubField("timeStamp")) timeStampRequested = true;
175  if(fieldPVStructure->getSubField("display")) displayRequested = true;
176  if(fieldPVStructure->getSubField("control")) controlRequested = true;
177  if(fieldPVStructure->getSubField("valueAlarm")) valueAlarmRequested = true;
178  }
179  switch(ioType)
180  {
181  case getIO : break;
182  case putIO:
183  alarmRequested = false;
184  timeStampRequested = false;
185  displayRequested = false;
186  controlRequested = false;
187  valueAlarmRequested = false;
188  break;
189  case monitorIO: break;
190  }
191  StandardFieldPtr standardField = getStandardField();
192  if(channelType==DBR_ENUM)
193  {
194  displayRequested = false;
195  controlRequested = false;
196  valueAlarmRequested = false;
197  string properties;
198  if(alarmRequested && timeStampRequested) {
199  properties += "alarm,timeStamp";
200  } else if(timeStampRequested) {
201  properties += "timeStamp";
202  } else if(alarmRequested) {
203  properties += "alarm";
204  }
205  caRequestType = (properties.size()==0 ? DBR_ENUM : DBR_TIME_ENUM);
206  structure = standardField->enumerated(properties);
207 
208  return;
209  }
210  ScalarType st = dbr2ST[channelType];
211  PVStringPtr pvValue = fieldPVStructure->getSubField<PVString>("value._options.dbtype");
212  if(pvValue)
213  {
214  std::string value(pvValue->get());
215  if(value.find("DBF_UCHAR")!=std::string::npos) {
216  if(st==pvByte) {
217  dbfIsUCHAR = true;
218  st = pvUByte;
219  caValueType = DBR_CHAR;
220  }
221  } else if(value.find("DBF_USHORT")!=std::string::npos) {
222  if(st==pvInt) {
223  dbfIsUSHORT = true;
224  st = pvUShort;
225  caValueType = DBR_SHORT;
226  }
227  } else if(value.find("DBF_ULONG")!=std::string::npos) {
228  if(st==pvDouble) {
229  dbfIsULONG = true;
230  st = pvUInt;
231  caValueType = DBR_LONG;
232  }
233  } else if(value.find("DBF_INT64")!=std::string::npos) {
234  if(st==pvDouble) {
235  dbfIsINT64 = true;
236  st = pvLong;
237  }
238  } else if(value.find("DBF_UINT64")!=std::string::npos) {
239  if(st==pvDouble) {
240  dbfIsUINT64 = true;
241  st = pvULong;
242  }
243  }
244 
245  }
246  if(st==pvString) {
247  displayRequested = false;
248  controlRequested = false;
249  valueAlarmRequested = false;
250  }
251  maxElements = ca_element_count(channelID);
252  if(maxElements!=1) isArray = true;
253  if(isArray)
254  {
255  controlRequested = false;
256  valueAlarmRequested = false;
257  if(channelType==DBR_CHAR && fieldPVStructure)
258  {
259  PVStringPtr pvValue = fieldPVStructure->getSubField<PVString>("value._options.pvtype");
260  if(pvValue) {
261  std::string value(pvValue->get());
262  if(value.find("pvString")!=std::string::npos) {
263  charArrayIsString = true;
264  st = pvString;
265  }
266  }
267  }
268  }
269 
270  if(controlRequested || displayRequested || valueAlarmRequested) timeStampRequested = false;
273  FieldBuilderPtr fieldBuilder(fieldCreate->createFieldBuilder());
274  if(valueRequested) {
275  if(isArray && !charArrayIsString) {
276  fieldBuilder->addArray("value",st);
277  } else {
278  fieldBuilder->add("value",st);
279  }
280  }
281  if(alarmRequested) fieldBuilder->add("alarm",standardField->alarm());
282  if(timeStampRequested) fieldBuilder->add("timeStamp",standardField->timeStamp());
283  if(displayRequested) fieldBuilder->add("display",standardField->display());
284  if(controlRequested) fieldBuilder->add("control",standardField->control());
285  if(valueAlarmRequested) {
286  switch(st)
287  {
288  case pvByte:
289  case pvUByte:
290  fieldBuilder->add("valueAlarm",standardField->byteAlarm()); break;
291  case pvShort:
292  case pvUShort:
293  fieldBuilder->add("valueAlarm",standardField->shortAlarm()); break;
294  case pvInt:
295  case pvUInt:
296  fieldBuilder->add("valueAlarm",standardField->intAlarm()); break;
297  case pvFloat:
298  fieldBuilder->add("valueAlarm",standardField->floatAlarm()); break;
299  case pvDouble:
300  case pvLong:
301  case pvULong:
302  fieldBuilder->add("valueAlarm",standardField->doubleAlarm()); break;
303  default:
304  throw std::runtime_error("DbDToPv::activate: bad type");
305  }
306  }
307  structure = fieldBuilder->createStructure();
308  caRequestType = caValueType;
309  if(displayRequested || controlRequested || valueAlarmRequested)
310  {
311  caRequestType = dbf_type_to_DBR_CTRL(caValueType);
312  } else if(timeStampRequested || alarmRequested) {
313  caRequestType = dbf_type_to_DBR_TIME(caValueType);
314  } else {
315  caRequestType = dbf_type_to_DBR(caValueType);
316  }
317 
318 }
319 
320 chtype DbdToPv::getRequestType()
321 {
322  if(caRequestType<0) {
323  throw std::runtime_error("DbDToPv::getRequestType: bad type");
324  }
325  return caRequestType;
326 }
327 
328 Structure::const_shared_pointer DbdToPv::getStructure()
329 {
330  return structure;
331 }
332 
333 
334 static void enumChoicesHandler(struct event_handler_args args)
335 {
336  DbdToPv *dbdToPv = static_cast<DbdToPv*>(args.usr);
337  dbdToPv->getChoicesDone(args);
338 }
339 
340 void DbdToPv::getChoicesDone(struct event_handler_args &args)
341 {
342  if(args.status!=ECA_NORMAL)
343  {
344  string message("DbdToPv::getChoicesDone ca_message ");
345  message += ca_message(args.status);
346  throw std::runtime_error(message);
347  }
348  const dbr_gr_enum* dbr_enum_p = static_cast<const dbr_gr_enum*>(args.dbr);
349  size_t num = dbr_enum_p->no_str;
350  choices.reserve(num);
351  for(size_t i=0; i<num; ++i) choices.push_back(string(&dbr_enum_p->strs[i][0]));
352  choicesEvent.signal();
353 }
354 
355 
356 void DbdToPv::getChoices(CAChannelPtr const & caChannel)
357 {
358  if(caRequestType==DBR_ENUM||caRequestType==DBR_TIME_ENUM)
359  {
360  caChannel->attachContext();
361  chid channelID = caChannel->getChannelID();
363  1,
364  channelID, enumChoicesHandler, this);
365  if (result == ECA_NORMAL) {
366  result = ca_flush_io();
367  choicesEvent.wait();
368  } else {
369  string mess(caChannel->getChannelName());
370  mess += " DbdToPv::activate getting enum cnoices ";
371  mess += ca_message(result);
372  throw std::runtime_error(mess);
373  }
374  }
375 }
376 
377 PVStructurePtr DbdToPv::createPVStructure()
378 {
379  return getPVDataCreate()->createPVStructure(structure);
380 }
381 
382 template<typename dbrT, typename pvT>
383 void copy_DBRScalar(const void * dbr, PVScalar::shared_pointer const & pvScalar)
384 {
385  std::tr1::shared_ptr<pvT> value = std::tr1::static_pointer_cast<pvT>(pvScalar);
386  value->put(static_cast<const dbrT*>(dbr)[0]);
387 }
388 
389 template<typename dbrT, typename pvT>
390 void copy_DBRScalarArray(const void * dbr, unsigned count, PVScalarArray::shared_pointer const & pvArray)
391 {
392  std::tr1::shared_ptr<pvT> value = std::tr1::static_pointer_cast<pvT>(pvArray);
393  typename pvT::svector temp(value->reuse());
394  temp.resize(count);
395  std::copy(
396  static_cast<const dbrT*>(dbr),
397  static_cast<const dbrT*>(dbr) + count,
398  temp.begin());
399  value->replace(freeze(temp));
400 }
401 
402 template<typename dbrT>
403 void get_DBRControl(const void * dbr, double *upper_ctrl_limit,double *lower_ctrl_limit)
404 {
405  *upper_ctrl_limit = static_cast<const dbrT*>(dbr)->upper_ctrl_limit;
406  *lower_ctrl_limit = static_cast<const dbrT*>(dbr)->lower_ctrl_limit;
407 }
408 
409 template<typename dbrT>
411  const void * dbr, double *upper_disp_limit,double *lower_disp_limit,string *units)
412 {
413  *upper_disp_limit = static_cast<const dbrT*>(dbr)->upper_disp_limit;
414  *lower_disp_limit = static_cast<const dbrT*>(dbr)->lower_disp_limit;
415  *units = static_cast<const dbrT*>(dbr)->units;
416 }
417 
418 template<typename dbrT>
420  const void * dbr,
421  double *upper_alarm_limit,double *upper_warning_limit,
422  double *lower_warning_limit,double *lower_alarm_limit)
423 {
424  *upper_alarm_limit = static_cast<const dbrT*>(dbr)->upper_alarm_limit;
425  *upper_warning_limit = static_cast<const dbrT*>(dbr)->upper_warning_limit;
426  *lower_warning_limit = static_cast<const dbrT*>(dbr)->lower_warning_limit;
427  *lower_alarm_limit = static_cast<const dbrT*>(dbr)->lower_alarm_limit;
428 }
429 
430 Status DbdToPv::getFromDBD(
431  PVStructurePtr const & pvStructure,
432  BitSet::shared_pointer const & bitSet,
433  struct event_handler_args &args)
434 {
435  if(args.status!=ECA_NORMAL)
436  {
437  Status errorStatus(Status::STATUSTYPE_ERROR, string(ca_message(args.status)));
438  return errorStatus;
439  }
440  if(valueRequested)
441  {
442  void * value = dbr_value_ptr(args.dbr,caRequestType);
443  if(isArray) {
444  long count = args.count;
445  PVScalarArrayPtr pvValue = pvStructure->getSubField<PVScalarArray>("value");
446  switch(caValueType) {
447  case DBR_STRING:
448  {
449  const dbr_string_t *dbrval = static_cast<const dbr_string_t *>(value);
450  PVStringArrayPtr pvValue = pvStructure->getSubField<PVStringArray>("value");
451  PVStringArray::svector arr(pvValue->reuse());
452  arr.resize(count);
453  std::copy(dbrval, dbrval + count, arr.begin());
454  pvValue->replace(freeze(arr));
455  break;
456  }
457  case DBR_CHAR:
458  if(charArrayIsString)
459  {
460  const char * pchar = static_cast<const char *>(value);
461  std::string str(pchar);
462  PVStringPtr pvValue(pvStructure->getSubField<PVString>("value"));
463  pvValue->put(str);
464  break;
465  }
466  if(dbfIsUCHAR)
467  {
468  copy_DBRScalarArray<dbr_char_t,PVUByteArray>(value,count,pvValue);
469  break;
470  }
471  copy_DBRScalarArray<dbr_char_t,PVByteArray>(value,count,pvValue);
472  break;
473  case DBR_SHORT:
474  if(dbfIsUSHORT)
475  {
476  copy_DBRScalarArray<dbr_short_t,PVUShortArray>(value,count,pvValue);
477  break;
478  }
479  copy_DBRScalarArray<dbr_short_t,PVShortArray>(value,count,pvValue);
480  break;
481  case DBR_LONG:
482  if(dbfIsULONG)
483  {
484  copy_DBRScalarArray<dbr_long_t,PVUIntArray>(value,count,pvValue);
485  break;
486  }
487  copy_DBRScalarArray<dbr_long_t,PVIntArray>(value,count,pvValue);
488  break;
489  case DBR_FLOAT:
490  copy_DBRScalarArray<dbr_float_t,PVFloatArray>(value,count,pvValue);
491  break;
492  case DBR_DOUBLE:
493  if(dbfIsINT64)
494  {
495  copy_DBRScalarArray<dbr_double_t,PVLongArray>(value,count,pvValue);
496  break;
497  }
498  if(dbfIsUINT64)
499  {
500  copy_DBRScalarArray<dbr_double_t,PVULongArray>(value,count,pvValue);
501  break;
502  }
503  copy_DBRScalarArray<dbr_double_t,PVDoubleArray>(value,count,pvValue);
504  break;
505  default:
506  Status errorStatus(
507  Status::STATUSTYPE_ERROR, string("DbdToPv::getFromDBD logic error"));
508  return errorStatus;
509  }
510  } else {
511  PVScalarPtr pvValue = pvStructure->getSubField<PVScalar>("value");
512  switch(caValueType) {
513  case DBR_ENUM:
514  {
515  const dbr_enum_t *dbrval = static_cast<const dbr_enum_t *>(value);
516  PVIntPtr value = pvStructure->getSubField<PVInt>("value.index");
517  value->put(*dbrval);
518  PVStringArrayPtr pvChoices
519  = pvStructure->getSubField<PVStringArray>("value.choices");
520  if(pvChoices->getLength()==0)
521  {
522  ConvertPtr convert = getConvert();
523  size_t n = choices.size();
524  pvChoices->setLength(n);
525  convert->fromStringArray(pvChoices,0,n,choices,0);
526  bitSet->set(pvStructure->getSubField("value")->getFieldOffset());
527  } else {
528  bitSet->set(value->getFieldOffset());
529  }
530  break;
531  }
532  case DBR_STRING: copy_DBRScalar<dbr_string_t,PVString>(value,pvValue); break;
533  case DBR_CHAR:
534  if(dbfIsUCHAR)
535  {
536  copy_DBRScalar<dbr_char_t,PVUByte>(value,pvValue);
537  break;
538  }
539  copy_DBRScalar<dbr_char_t,PVByte>(value,pvValue); break;
540  case DBR_SHORT:
541  if(dbfIsUSHORT)
542  {
543  copy_DBRScalar<dbr_short_t,PVUShort>(value,pvValue);
544  break;
545  }
546  copy_DBRScalar<dbr_short_t,PVShort>(value,pvValue); break;
547  case DBR_LONG:
548  if(dbfIsULONG)
549  {
550  copy_DBRScalar<dbr_long_t,PVUInt>(value,pvValue);
551  break;
552  }
553  copy_DBRScalar<dbr_long_t,PVInt>(value,pvValue); break;
554  case DBR_FLOAT: copy_DBRScalar<dbr_float_t,PVFloat>(value,pvValue); break;
555  case DBR_DOUBLE:
556  if(dbfIsINT64)
557  {
558  copy_DBRScalar<dbr_double_t,PVLong>(value,pvValue);
559  break;
560  }
561  if(dbfIsUINT64)
562  {
563  copy_DBRScalar<dbr_double_t,PVULong>(value,pvValue);
564  break;
565  }
566  copy_DBRScalar<dbr_double_t,PVDouble>(value,pvValue); break;
567  default:
568  Status errorStatus(
569  Status::STATUSTYPE_ERROR, string("DbdToPv::getFromDBD logic error"));
570  return errorStatus;
571  }
572  }
573  if(caValueType!=DBR_ENUM) {
574  bitSet->set(pvStructure->getSubField("value")->getFieldOffset());
575  }
576  }
577  if(alarmRequested) {
578  // Note that status and severity are aways the first two members of DBR_
579  const dbr_sts_string *data = static_cast<const dbr_sts_string *>(args.dbr);
580  dbr_short_t status = data->status;
581  dbr_short_t severity = data->severity;
582  bool statusChanged = false;
583  bool severityChanged = false;
584  PVStructurePtr pvAlarm(pvStructure->getSubField<PVStructure>("alarm"));
585  PVIntPtr pvSeverity(pvAlarm->getSubField<PVInt>("severity"));
586  if(caAlarm.severity!=severity) {
587  caAlarm.severity = severity;
588  pvSeverity->put(severity);
589  severityChanged = true;
590  }
591  PVStringPtr pvMessage(pvAlarm->getSubField<PVString>("message"));
592  PVIntPtr pvStatus(pvAlarm->getSubField<PVInt>("status"));
593  if(caAlarm.status!=status) {
594  caAlarm.status = status;
595  pvStatus->put(convertDBstatus(status));
596  string message("UNKNOWN STATUS");
597  if(status<=ALARM_NSTATUS) message = string(epicsAlarmConditionStrings[status]);
598  pvMessage->put(message);
599  statusChanged = true;
600  }
601  if(statusChanged&&severityChanged) {
602  bitSet->set(pvAlarm->getFieldOffset());
603  } else if(severityChanged) {
604  bitSet->set(pvSeverity->getFieldOffset());
605  } else if(statusChanged) {
606  bitSet->set(pvStatus->getFieldOffset());
607  bitSet->set(pvMessage->getFieldOffset());
608  }
609  }
610  if(timeStampRequested) {
611  // Note that epicsTimeStamp always follows status and severity
612  const dbr_time_string *data = static_cast<const dbr_time_string *>(args.dbr);
613  epicsTimeStamp stamp = data->stamp;
614  PVStructurePtr pvTimeStamp(pvStructure->getSubField<PVStructure>("timeStamp"));
615  if(caTimeStamp.secPastEpoch!=stamp.secPastEpoch) {
616  caTimeStamp.secPastEpoch = stamp.secPastEpoch;
617  PVLongPtr pvSeconds(pvTimeStamp->getSubField<PVLong>("secondsPastEpoch"));
618  pvSeconds->put(stamp.secPastEpoch+posixEpochAtEpicsEpoch);
619  bitSet->set(pvSeconds->getFieldOffset());
620  }
621  if(caTimeStamp.nsec!=stamp.nsec) {
622  caTimeStamp.nsec = stamp.nsec;
623  PVIntPtr pvNano(pvTimeStamp->getSubField<PVInt>("nanoseconds"));
624  pvNano->put(stamp.nsec);
625  bitSet->set(pvNano->getFieldOffset());
626  }
627  }
628  if(controlRequested)
629  {
630  double upper_ctrl_limit = 0.0;
631  double lower_ctrl_limit = 0.0;
632  switch(caRequestType) {
633  case DBR_CTRL_CHAR:
634  get_DBRControl<dbr_ctrl_char>(args.dbr,&upper_ctrl_limit,&lower_ctrl_limit); break;
635  case DBR_CTRL_SHORT:
636  get_DBRControl<dbr_ctrl_short>(args.dbr,&upper_ctrl_limit,&lower_ctrl_limit); break;
637  case DBR_CTRL_LONG:
638  get_DBRControl<dbr_ctrl_long>(args.dbr,&upper_ctrl_limit,&lower_ctrl_limit); break;
639  case DBR_CTRL_FLOAT:
640  get_DBRControl<dbr_ctrl_float>(args.dbr,&upper_ctrl_limit,&lower_ctrl_limit); break;
641  case DBR_CTRL_DOUBLE:
642  get_DBRControl<dbr_ctrl_double>(args.dbr,&upper_ctrl_limit,&lower_ctrl_limit); break;
643  default :
644  throw std::runtime_error("DbdToPv::getFromDBD logic error");
645  }
646  PVStructurePtr pvControl(pvStructure->getSubField<PVStructure>("control"));
647  if(caControl.upper_ctrl_limit!=upper_ctrl_limit) {
648  caControl.upper_ctrl_limit = upper_ctrl_limit;
649  PVDoublePtr pv = pvControl->getSubField<PVDouble>("limitHigh");
650  pv->put(upper_ctrl_limit);
651  bitSet->set(pv->getFieldOffset());
652  }
653  if(caControl.lower_ctrl_limit!=lower_ctrl_limit) {
654  caControl.lower_ctrl_limit = lower_ctrl_limit;
655  PVDoublePtr pv = pvControl->getSubField<PVDouble>("limitLow");
656  pv->put(lower_ctrl_limit);
657  bitSet->set(pv->getFieldOffset());
658  }
659  }
660  if(displayRequested)
661  {
662  string units;
663  string format;
664  double upper_disp_limit = 0.0;
665  double lower_disp_limit = 0.0;
666  switch(caRequestType) {
667  case DBR_CTRL_CHAR:
668  get_DBRDisplay<dbr_ctrl_char>(args.dbr,&upper_disp_limit,&lower_disp_limit,&units);
669  format = "I4"; break;
670  case DBR_CTRL_SHORT:
671  get_DBRDisplay<dbr_ctrl_short>(args.dbr,&upper_disp_limit,&lower_disp_limit,&units);
672  format = "I6"; break;
673  case DBR_CTRL_LONG:
674  get_DBRDisplay<dbr_ctrl_long>(args.dbr,&upper_disp_limit,&lower_disp_limit,&units);
675  format = "I12"; break;
676  case DBR_CTRL_FLOAT:
677  get_DBRDisplay<dbr_ctrl_float>(args.dbr,&upper_disp_limit,&lower_disp_limit,&units);
678  {
679  const dbr_ctrl_float *data = static_cast<const dbr_ctrl_float *>(args.dbr);
680  int prec = data->precision;
681  ostringstream s;
682  s << "F" << prec + 6 << "." << prec;
683  format = s.str();
684  }
685  break;
686  case DBR_CTRL_DOUBLE:
687  get_DBRDisplay<dbr_ctrl_double>(args.dbr,&upper_disp_limit,&lower_disp_limit,&units);
688  {
689  const dbr_ctrl_double *data = static_cast<const dbr_ctrl_double *>(args.dbr);
690  int prec = data->precision;
691  ostringstream s;
692  s << "F" << prec + 6 << "." << prec;
693  format = s.str();
694  }
695  break;
696  default :
697  throw std::runtime_error("DbdToPv::getFromDBD logic error");
698  }
699  PVStructurePtr pvDisplay(pvStructure->getSubField<PVStructure>("display"));
700  if(caDisplay.lower_disp_limit!=lower_disp_limit) {
701  caDisplay.lower_disp_limit = lower_disp_limit;
702  PVDoublePtr pvDouble = pvDisplay->getSubField<PVDouble>("limitLow");
703  pvDouble->put(lower_disp_limit);
704  bitSet->set(pvDouble->getFieldOffset());
705  }
706  if(caDisplay.upper_disp_limit!=upper_disp_limit) {
707  caDisplay.upper_disp_limit = upper_disp_limit;
708  PVDoublePtr pvDouble = pvDisplay->getSubField<PVDouble>("limitHigh");
709  pvDouble->put(upper_disp_limit);
710  bitSet->set(pvDouble->getFieldOffset());
711  }
712  if(caDisplay.units!=units) {
713  caDisplay.units = units;
714  PVStringPtr pvString = pvDisplay->getSubField<PVString>("units");
715  pvString->put(units);
716  bitSet->set(pvString->getFieldOffset());
717  }
718  if(caDisplay.format!=format) {
719  caDisplay.format = format;
720  PVStringPtr pvString = pvDisplay->getSubField<PVString>("format");
721  if(pvString) {
722  pvString->put(format);
723  bitSet->set(pvString->getFieldOffset());
724  }
725  }
726  }
727  if(valueAlarmRequested) {
728  double upper_alarm_limit = 0.0;
729  double upper_warning_limit = 0.0;
730  double lower_warning_limit = 0.0;
731  double lower_alarm_limit = 0.0;
732  switch(caRequestType) {
733  case DBR_CTRL_CHAR:
734  get_DBRValueAlarm<dbr_ctrl_char>(args.dbr,
735  &upper_alarm_limit,&upper_warning_limit,
736  &lower_warning_limit,&lower_alarm_limit);
737  break;
738  case DBR_CTRL_SHORT:
739  get_DBRValueAlarm<dbr_ctrl_short>(args.dbr,
740  &upper_alarm_limit,&upper_warning_limit,
741  &lower_warning_limit,&lower_alarm_limit);
742  break;
743  case DBR_CTRL_LONG:
744  get_DBRValueAlarm<dbr_ctrl_long>(args.dbr,
745  &upper_alarm_limit,&upper_warning_limit,
746  &lower_warning_limit,&lower_alarm_limit);
747  break;
748  case DBR_CTRL_FLOAT:
749  get_DBRValueAlarm<dbr_ctrl_float>(args.dbr,
750  &upper_alarm_limit,&upper_warning_limit,
751  &lower_warning_limit,&lower_alarm_limit);
752  break;
753  case DBR_CTRL_DOUBLE:
754  get_DBRValueAlarm<dbr_ctrl_double>(args.dbr,
755  &upper_alarm_limit,&upper_warning_limit,
756  &lower_warning_limit,&lower_alarm_limit);
757  break;
758  default :
759  throw std::runtime_error("DbdToPv::getFromDBD logic error");
760  }
761  ConvertPtr convert(getConvert());
762  PVStructurePtr pvValueAlarm(pvStructure->getSubField<PVStructure>("valueAlarm"));
763  if(caValueAlarm.upper_alarm_limit!=upper_alarm_limit) {
764  caValueAlarm.upper_alarm_limit = upper_alarm_limit;
765  PVScalarPtr pv = pvValueAlarm->getSubField<PVScalar>("highAlarmLimit");
766  convert->fromDouble(pv,upper_alarm_limit);
767  bitSet->set(pv->getFieldOffset());
768  }
769  if(caValueAlarm.upper_warning_limit!=upper_warning_limit) {
770  caValueAlarm.upper_warning_limit = upper_warning_limit;
771  PVScalarPtr pv = pvValueAlarm->getSubField<PVScalar>("highWarningLimit");
772  convert->fromDouble(pv,upper_warning_limit);
773  bitSet->set(pv->getFieldOffset());
774  }
775  if(caValueAlarm.lower_warning_limit!=lower_warning_limit) {
776  caValueAlarm.lower_warning_limit = lower_warning_limit;
777  PVScalarPtr pv = pvValueAlarm->getSubField<PVScalar>("lowWarningLimit");
778  convert->fromDouble(pv,lower_warning_limit);
779  bitSet->set(pv->getFieldOffset());
780  }
781  if(caValueAlarm.lower_alarm_limit!=lower_alarm_limit) {
782  caValueAlarm.lower_alarm_limit = lower_alarm_limit;
783  PVScalarPtr pv = pvValueAlarm->getSubField<PVScalar>("lowAlarmLimit");
784  convert->fromDouble(pv,lower_alarm_limit);
785  bitSet->set(pv->getFieldOffset());
786  }
787  }
788  if(firstTime) {
789  firstTime = false;
790  bitSet->clear();
791  bitSet->set(0);
792  }
793  return Status::Ok;
794 }
795 
796 
797 
798 template<typename dbrT, typename pvT>
799 const void * put_DBRScalar(dbrT *val,PVScalar::shared_pointer const & pvScalar)
800 {
801  std::tr1::shared_ptr<pvT> value = std::tr1::static_pointer_cast<pvT>(pvScalar);
802  *val = value->get();
803  return val;
804 }
805 
806 template<typename dbrT, typename pvT>
807 const void * put_DBRScalarArray(unsigned long*count, PVScalarArray::shared_pointer const & pvArray)
808 {
809  std::tr1::shared_ptr<pvT> value = std::tr1::static_pointer_cast<pvT>(pvArray);
810  *count = value->getLength();
811  return value->view().data();
812 }
813 
814 
815 Status DbdToPv::putToDBD(
816  CAChannelPtr const & caChannel,
817  PVStructurePtr const & pvStructure,
818  bool block,
819  caCallbackFunc putHandler,
820  void * userarg)
821 {
822  chid channelID = caChannel->getChannelID();
823  const void *pValue = NULL;
824  unsigned long count = 1;
825  char *ca_stringBuffer(0);
826  dbr_char_t bvalue(0);
827  dbr_short_t svalue(0);
828  dbr_long_t lvalue(0);
829  dbr_float_t fvalue(0);
830  dbr_double_t dvalue(0);
831  if(isArray) {
832  PVScalarArrayPtr pvValue = pvStructure->getSubField<PVScalarArray>("value");
833  switch(caValueType) {
834  case DBR_STRING:
835  {
836  PVStringArrayPtr pvValue = pvStructure->getSubField<PVStringArray>("value");
837  count = pvValue->getLength();
838  if(count<1) break;
839  if(count>maxElements) count = maxElements;
840  int nbytes = count*MAX_STRING_SIZE;
841  ca_stringBuffer = new char[nbytes];
842  memset(ca_stringBuffer, 0, nbytes);
843  pValue = ca_stringBuffer;
844  PVStringArray::const_svector stringArray(pvValue->view());
845  char *pnext = ca_stringBuffer;
846  for(size_t i=0; i<count; ++i) {
847  string value = stringArray[i];
848  size_t len = value.length();
849  if (len >= MAX_STRING_SIZE) len = MAX_STRING_SIZE - 1;
850  memcpy(pnext, value.c_str(), len);
851  pnext += MAX_STRING_SIZE;
852  }
853  break;
854  }
855  case DBR_CHAR:
856  if(charArrayIsString)
857  {
858  PVStringPtr pvValue(pvStructure->getSubField<PVString>("value"));
859  const char * pchar = pvValue->get().c_str();
860  pValue = pchar;
861  count = pvValue->get().length();
862  break;
863  }
864  if(dbfIsUCHAR)
865  {
866  pValue = put_DBRScalarArray<dbr_char_t,PVUByteArray>(&count,pvValue);
867  break;
868  }
869  pValue = put_DBRScalarArray<dbr_char_t,PVByteArray>(&count,pvValue);
870  break;
871  case DBR_SHORT:
872  if(dbfIsUSHORT)
873  {
874  pValue = put_DBRScalarArray<dbr_short_t,PVUShortArray>(&count,pvValue);
875  break;
876  }
877  pValue = put_DBRScalarArray<dbr_short_t,PVShortArray>(&count,pvValue);
878  break;
879  case DBR_LONG:
880  if(dbfIsULONG)
881  {
882  pValue = put_DBRScalarArray<dbr_long_t,PVUIntArray>(&count,pvValue);
883  break;
884  }
885  pValue = put_DBRScalarArray<dbr_long_t,PVIntArray>(&count,pvValue);
886  break;
887  case DBR_FLOAT:
888  pValue = put_DBRScalarArray<dbr_float_t,PVFloatArray>(&count,pvValue);
889  break;
890  case DBR_DOUBLE:
891  if(dbfIsINT64)
892  {
893  PVLongArrayPtr pvValue(pvStructure->getSubField<PVLongArray>("value"));
894  PVLongArray::const_svector sv(pvValue->view());
895  pvDoubleArray = PVDoubleArrayPtr(getPVDataCreate()->createPVScalarArray<PVDoubleArray>());
896  pvDoubleArray->putFrom(sv);
897  const double * pdouble = pvDoubleArray->view().data();
898  count = pvValue->getLength();
899  pValue = pdouble;
900  break;
901  }
902  if(dbfIsUINT64)
903  {
904  PVULongArrayPtr pvValue(pvStructure->getSubField<PVULongArray>("value"));
905  PVULongArray::const_svector sv(pvValue->view());
906  pvDoubleArray = PVDoubleArrayPtr(getPVDataCreate()->createPVScalarArray<PVDoubleArray>());
907  pvDoubleArray->putFrom(sv);
908  const double * pdouble = pvDoubleArray->view().data();
909  count = pvValue->getLength();
910  pValue = pdouble;
911  break;
912  }
913  pValue = put_DBRScalarArray<dbr_double_t,PVDoubleArray>(&count,pvValue);
914  break;
915  default:
916  Status errorStatus(
917  Status::STATUSTYPE_ERROR, string("DbdToPv::getFromDBD logic error"));
918  return errorStatus;
919  }
920  } else {
921  PVScalarPtr pvValue = pvStructure->getSubField<PVScalar>("value");
922  switch(caValueType) {
923  case DBR_ENUM:
924  {
925  dbr_enum_t indexvalue = pvStructure->getSubField<PVInt>("value.index")->get();
926  pValue = &indexvalue;
927  break;
928  }
929  case DBR_STRING: pValue = pvStructure->getSubField<PVString>("value")->get().c_str(); break;
930  case DBR_CHAR:
931  if(dbfIsUCHAR)
932  {
933  pValue = put_DBRScalar<dbr_char_t,PVUByte>(&bvalue,pvValue);
934  break;
935  }
936  pValue = put_DBRScalar<dbr_char_t,PVByte>(&bvalue,pvValue); break;
937  case DBR_SHORT:
938  if(dbfIsUSHORT)
939  {
940  pValue = put_DBRScalar<dbr_short_t,PVUShort>(&svalue,pvValue);
941  break;
942  }
943  pValue = put_DBRScalar<dbr_short_t,PVShort>(&svalue,pvValue); break;
944  case DBR_LONG:
945  if(dbfIsULONG)
946  {
947  pValue = put_DBRScalar<dbr_long_t,PVUInt>(&lvalue,pvValue);
948  break;
949  }
950  pValue = put_DBRScalar<dbr_long_t,PVInt>(&lvalue,pvValue); break;
951  case DBR_FLOAT: pValue = put_DBRScalar<dbr_float_t,PVFloat>(&fvalue,pvValue); break;
952  case DBR_DOUBLE:
953  if(dbfIsINT64)
954  {
955  pValue = put_DBRScalar<dbr_double_t,PVLong>(&dvalue,pvValue);
956  break;
957  }
958  if(dbfIsUINT64)
959  {
960  pValue = put_DBRScalar<dbr_double_t,PVULong>(&dvalue,pvValue);
961  break;
962  }
963  pValue = put_DBRScalar<dbr_double_t,PVDouble>(&dvalue,pvValue); break;
964  default:
965  Status errorStatus(
966  Status::STATUSTYPE_ERROR, string("DbdToPv::putToDBD logic error"));
967  return errorStatus;
968  }
969  }
971  int result = 0;
972  caChannel->attachContext();
973  if(block) {
974  result = ca_array_put_callback(caValueType,count,channelID,pValue,putHandler,userarg);
975  } else {
976  result = ca_array_put(caValueType,count,channelID,pValue);
977  }
978  if(result==ECA_NORMAL) {
979  ca_flush_io();
980  } else {
981  status = Status(Status::STATUSTYPE_ERROR, string(ca_message(result)));
982  }
983  if(ca_stringBuffer!=NULL) delete[] ca_stringBuffer;
984  return status;
985 }
986 
987 }}}
#define HIHI_ALARM
Definition: alarm.h:94
#define DBR_CHAR
Definition: db_access.h:74
#define DBR_STRING
Definition: db_access.h:69
const void * put_DBRScalarArray(unsigned long *count, PVScalarArray::shared_pointer const &pvArray)
Definition: dbdToPv.cpp:807
void resize(size_t i)
Grow or shrink array.
Definition: sharedVector.h:457
dbr_short_t severity
Definition: db_access.h:178
Definition: link.h:174
LIBCA_API int epicsStdCall ca_array_get_callback(chtype type, unsigned long count, chid chanId, caEventCallBackFunc *pFunc, void *pArg)
PVScalar is the base class for each scalar field.
Definition: pvData.h:272
std::tr1::shared_ptr< PVInt > PVIntPtr
Definition: pvData.h:507
pvac::PutEvent result
Definition: clientSync.cpp:117
const void * dbr
Definition: cadef.h:89
A holder for a contiguous piece of memory.
Definition: sharedVector.h:27
dbr_short_t status
Definition: db_access.h:177
void get_DBRDisplay(const void *dbr, double *upper_disp_limit, double *lower_disp_limit, string *units)
Definition: dbdToPv.cpp:410
#define READ_ALARM
Definition: alarm.h:92
pvd::Status status
static Status Ok
Definition: status.h:47
int i
Definition: scan.c:967
LIBCA_API int epicsStdCall ca_array_put_callback(chtype type, unsigned long count, chid chanId, const void *pValue, caEventCallBackFunc *pFunc, void *pArg)
#define DBR_GR_ENUM
Definition: db_access.h:97
LIBCA_API unsigned long epicsStdCall ca_element_count(chid chan)
Definition: tool_lib.h:67
epicsFloat32 dbr_float_t
Definition: db_access.h:46
shared_ptr< T > static_pointer_cast(shared_ptr< U > const &r) BOOST_NOEXCEPT
Definition: shared_ptr.hpp:788
#define DBR_FLOAT
Definition: db_access.h:72
TODO only here because of the Lockable.
Definition: ntaggregate.cpp:16
#define SOFT_ALARM
Definition: alarm.h:106
#define NULL
Definition: catime.c:38
#define dbf_type_to_DBR(type)
Definition: db_access.h:697
#define str(v)
std::tr1::shared_ptr< PVLong > PVLongPtr
Definition: pvData.h:508
LIBCA_API short epicsStdCall ca_field_type(chid chan)
std::tr1::shared_ptr< PVStringArray > PVStringArrayPtr
Definition: pvData.h:1464
std::tr1::shared_ptr< FieldBuilder > FieldBuilderPtr
#define DISABLE_ALARM
Definition: alarm.h:109
void copy(PVValueArray< T > &pvFrom, size_t fromOffset, size_t fromStride, PVValueArray< T > &pvTo, size_t toOffset, size_t toStride, size_t count)
Copy a subarray from one scalar array to another.
std::tr1::shared_ptr< CAChannel > CAChannelPtr
Definition: caChannel.h:31
#define SCAN_ALARM
Definition: alarm.h:104
std::tr1::shared_ptr< StandardField > StandardFieldPtr
Definition: standardField.h:22
#define DBR_CTRL_FLOAT
Definition: db_access.h:104
epicsUInt32 secPastEpoch
seconds since 0000 Jan 1, 1990
Definition: epicsTime.h:34
std::tr1::shared_ptr< PVDataCreate > PVDataCreatePtr
Definition: pvData.h:124
#define COS_ALARM
Definition: alarm.h:99
#define READ_ACCESS_ALARM
Definition: alarm.h:111
#define HIGH_ALARM
Definition: alarm.h:95
#define dbr_value_ptr(PDBR, DBR_TYPE)
Definition: db_access.h:540
PVString is special case, since it implements SerializableArray.
Definition: pvData.h:521
#define HW_LIMIT_ALARM
Definition: alarm.h:102
FORCE_INLINE const StandardFieldPtr & getStandardField()
pvData
Definition: monitor.h:428
#define CALC_ALARM
Definition: alarm.h:103
#define ECA_NORMAL
Definition: caerr.h:77
void get_DBRValueAlarm(const void *dbr, double *upper_alarm_limit, double *upper_warning_limit, double *lower_warning_limit, double *lower_alarm_limit)
Definition: dbdToPv.cpp:419
#define DBR_CTRL_SHORT
Definition: db_access.h:102
LIBCA_API int epicsStdCall ca_array_put(chtype type, unsigned long count, chid chanId, const void *pValue)
template class for all extensions of PVArray.
Definition: pvData.h:55
int epicsStdCall ca_flush_io()
Definition: access.cpp:509
#define SIMM_ALARM
Definition: alarm.h:110
#define DBR_TIME_ENUM
Definition: db_access.h:89
#define DBR_DOUBLE
Definition: db_access.h:76
#define NO_ALARM
The NO_ALARM value can be used as both a severity and a status.
Definition: alarm.h:32
Deprecated, use alarm.h instead.
#define DBR_CTRL_CHAR
Definition: db_access.h:106
DbdToPv converts between DBD data and pvData.
Definition: dbdToPv.h:83
#define DBR_SHORT
Definition: db_access.h:71
Base class for a scalarArray.
Definition: pvData.h:618
std::tr1::shared_ptr< PVScalar > PVScalarPtr
Definition: pvData.h:77
epicsFloat64 dbr_double_t
Definition: db_access.h:47
std::tr1::shared_ptr< PVULongArray > PVULongArrayPtr
Definition: pvData.h:1455
epicsTimeStamp stamp
Definition: db_access.h:245
epicsOldString dbr_string_t
Definition: db_access.h:38
Data interface for a structure,.
Definition: pvData.h:712
std::tr1::shared_ptr< PVLongArray > PVLongArrayPtr
Definition: pvData.h:1443
#define LINK_ALARM
Definition: alarm.h:105
dbr_short_t no_str
Definition: db_access.h:353
epicsUInt8 dbr_char_t
Definition: db_access.h:39
static const PVDataCreatePtr & getPVDataCreate()
void( caCallbackFunc)(struct event_handler_args)
Definition: dbdToPv.h:76
void put(typename storage_t::arg_type v)
Definition: pvData.h:401
dbr_short_t precision
Definition: db_access.h:504
std::tr1::shared_ptr< PVStructure > PVStructurePtr
Definition: pvData.h:87
dbr_short_t precision
Definition: db_access.h:443
#define BAD_SUB_ALARM
Definition: alarm.h:107
#define DBR_ENUM
Definition: db_access.h:73
epicsUInt16 dbr_enum_t
Definition: db_access.h:43
std::tr1::shared_ptr< PVString > PVStringPtr
Definition: pvData.h:540
const char *epicsStdCall ca_message(long ca_status)
Definition: access.cpp:561
#define DBR_CTRL_LONG
Definition: db_access.h:107
long chtype
Definition: cadef.h:47
#define TIMEOUT_ALARM
Definition: alarm.h:101
#define DBR_LONG
Definition: db_access.h:75
Class that holds the data for each possible scalar type.
Definition: pvData.h:54
#define MAX_STRING_SIZE
Definition: epicsTypes.h:65
EPICS time stamp, for use from C code.
Definition: epicsTime.h:33
std::tr1::shared_ptr< FieldCreate > FieldCreatePtr
std::tr1::shared_ptr< DbdToPv > DbdToPvPtr
Definition: dbdToPv.h:73
std::tr1::shared_ptr< Convert > ConvertPtr
Definition: convert.h:23
virtual size_t getLength() const OVERRIDE FINAL
Definition: pvData.h:1203
epicsShareExtern const int64 posixEpochAtEpicsEpoch
Definition: timeStamp.h:25
#define STATE_ALARM
Definition: alarm.h:98
const void * put_DBRScalar(dbrT *val, PVScalar::shared_pointer const &pvScalar)
Definition: dbdToPv.cpp:799
epicsInt16 dbr_short_t
Definition: db_access.h:40
epicsInt32 dbr_long_t
Definition: db_access.h:44
int prec
Definition: reader.c:29
std::tr1::shared_ptr< PVScalarArray > PVScalarArrayPtr
Definition: pvData.h:82
void copy_DBRScalar(const void *dbr, PVScalar::shared_pointer const &pvScalar)
Definition: dbdToPv.cpp:383
#define LOLO_ALARM
Definition: alarm.h:96
LIBCOM_API const char * epicsAlarmConditionStrings[ALARM_NSTATUS]
How to convert an alarm condition/status into a string.
Definition: alarmString.c:26
#define WRITE_ACCESS_ALARM
Definition: alarm.h:112
#define LOW_ALARM
Definition: alarm.h:97
#define DBR_CTRL_DOUBLE
Definition: db_access.h:108
std::tr1::shared_ptr< PVDoubleArray > PVDoubleArrayPtr
Definition: pvData.h:1461
static const FieldCreatePtr & getFieldCreate()
void * usr
Definition: cadef.h:85
void get_DBRControl(const void *dbr, double *upper_ctrl_limit, double *lower_ctrl_limit)
Definition: dbdToPv.cpp:403
#define COMM_ALARM
Definition: alarm.h:100
FORCE_INLINE const PVDataCreatePtr & getPVDataCreate()
Definition: pvData.h:1648
std::tr1::shared_ptr< PVDouble > PVDoublePtr
Definition: pvData.h:514
void copy_DBRScalarArray(const void *dbr, unsigned count, PVScalarArray::shared_pointer const &pvArray)
Definition: dbdToPv.cpp:390
#define dbf_type_to_DBR_CTRL(type)
Definition: db_access.h:713
void getChoicesDone(struct event_handler_args &args)
Definition: dbdToPv.cpp:340
epicsUInt32 nsec
nanoseconds within second
Definition: epicsTime.h:35
#define UDF_ALARM
Definition: alarm.h:108
char strs[MAX_ENUM_STATES][MAX_ENUM_STRING_SIZE]
Definition: db_access.h:354
#define WRITE_ALARM
Definition: alarm.h:93
#define dbf_type_to_DBR_TIME(type)
Definition: db_access.h:705