This is Unofficial EPICS BASE Doxygen Site
pvif.cpp
Go to the documentation of this file.
1 
2 
3 #include <pv/pvIntrospect.h> /* for pvdVersion.h */
4 #include <pv/standardField.h>
5 
6 #include <dbAccess.h>
7 #include <dbChannel.h>
8 #include <dbStaticLib.h>
9 #include <dbLock.h>
10 #include <dbEvent.h>
11 #include <alarm.h>
12 #include <errSymTbl.h>
13 #include <epicsVersion.h>
14 #include <errlog.h>
15 #include <osiSock.h>
16 
17 #include <pv/status.h>
18 #include <pv/bitSet.h>
19 #include <pv/pvData.h>
20 #include <pv/anyscalar.h>
21 #include <pv/reftrack.h>
22 #include <pv/pvAccess.h>
23 #include <pv/security.h>
24 
25 #include "sb.h"
26 #include "pvif.h"
27 
28 #include <epicsExport.h>
29 
30 #ifdef EPICS_VERSION_INT
31 # if EPICS_VERSION_INT>=VERSION_INT(3,16,1,0)
32 # define USE_INT64
33  // effects all uses of pv/typemap.h
34 # define CASE_REAL_INT64
35 # endif
36 #endif
37 
38 namespace pvd = epics::pvData;
39 namespace pva = epics::pvAccess;
40 
41 DBCH::DBCH(dbChannel *ch) :chan(ch)
42 {
43  prepare();
44 }
45 
46 DBCH::DBCH(const std::string& name)
47  :chan(dbChannelCreate(name.c_str()))
48 {
49  prepare();
50 }
51 
52 void DBCH::prepare()
53 {
54  if(!chan)
55  throw std::invalid_argument("NULL channel");
56  if(dbChannelOpen(chan)) {
57  dbChannelDelete(chan);
58  throw std::invalid_argument(SB()<<"Failed to open channel "<<dbChannelName(chan));
59  }
60 }
61 
63 {
64  if(chan) dbChannelDelete(chan);
65 }
66 
67 void DBCH::swap(DBCH& o)
68 {
69  std::swap(chan, o.chan);
70 }
71 
72 void ASCred::update(const pva::ChannelRequester::shared_pointer& req)
73 {
74  pva::PeerInfo::const_shared_pointer info(req->getPeerInfo());
75  std::string usertemp, hosttemp;
76 
77  if(info && info->identified) {
78  hosttemp = info->peer;
79  if(info->authority=="ca") {
80  usertemp = info->account;
81  size_t sep = usertemp.find_last_of('/');
82  if(sep != std::string::npos) {
83  // prevent CA auth from claiming to be eg. "krb/someone.special"
84  usertemp = usertemp.substr(sep+1);
85  }
86 
87  } else {
88  usertemp = info->authority + "/" + info->account;
89  }
90 
91  const char role[] = "role/";
92 
93  groups.resize(info->roles.size());
94  size_t idx = 0u;
95  for(pva::PeerInfo::roles_t::const_iterator it(info->roles.begin()), end(info->roles.end()); it!=end; ++it, idx++) {
96  groups[idx].resize((*it).size()+sizeof(role)); // sizeof(role) includes trailing nil
97  std::copy(role,
98  role+sizeof(role)-1,
99  groups[idx].begin());
100  std::copy(it->begin(),
101  it->end(),
102  groups[idx].begin()+sizeof(role)-1);
103  groups[idx][groups[idx].size()-1] = '\0';
104  }
105 
106  } else {
107  // legacy and anonymous
108  hosttemp = req->getRequesterName();
109  }
110 
111  // remote names have the form "IP:port"
112  size_t sep = hosttemp.find_first_of(':');
113  if(sep == std::string::npos) {
114  sep = hosttemp.size();
115  }
116  hosttemp.resize(sep);
117 
118  host.resize(hosttemp.size()+1);
119  std::copy(hosttemp.begin(),
120  hosttemp.end(),
121  host.begin());
122  host[hosttemp.size()] = '\0';
123 
124  user.resize(usertemp.size()+1);
125  std::copy(usertemp.begin(),
126  usertemp.end(),
127  user.begin());
128  user[usertemp.size()] = '\0';
129 }
130 
132 {
133  asRemoveClient(&aspvt);
134  for(size_t i=0, N=grppvt.size(); i<N; i++) {
135  asRemoveClient(&grppvt[i]);
136  }
137 }
138 
139 void ASCLIENT::add(dbChannel* chan, ASCred& cred)
140 {
141  asRemoveClient(&aspvt);
142  /* asAddClient() fails secure to no-permission */
143  (void)asAddClient(&aspvt, dbChannelRecord(chan)->asp, dbChannelFldDes(chan)->as_level, &cred.user[0], &cred.host[0]);
144 
145  grppvt.resize(cred.groups.size(), 0);
146 
147  for(size_t i=0, N=grppvt.size(); i<N; i++) {
148  asRemoveClient(&grppvt[i]);
149  (void)asAddClient(&grppvt[i], dbChannelRecord(chan)->asp, dbChannelFldDes(chan)->as_level, &cred.groups[i][0], &cred.host[0]);
150  }
151 }
152 
154  if(!asActive || (aspvt && asCheckPut(aspvt)))
155  return true;
156  for(size_t i=0, N=grppvt.size(); i<N; i++) {
157  if(grppvt[i] && asCheckPut(grppvt[i]))
158  return true;
159  }
160  return false;
161 }
162 
163 PVIF::PVIF(dbChannel *ch)
164  :chan(ch)
165 {}
166 
167 namespace {
168 
169 struct pvTimeAlarm {
170  dbChannel *chan;
171 
172  pvd::uint32 nsecMask;
173 
174  pvd::BitSet maskALWAYS, maskALARM;
175 
176  pvd::PVLongPtr sec;
177  pvd::PVIntPtr status, severity, nsec, userTag;
178  pvd::PVStringPtr message;
179 
180  pvTimeAlarm() :chan(NULL), nsecMask(0) {}
181 };
182 
183 struct pvCommon : public pvTimeAlarm {
184 
185  pvd::BitSet maskVALUE, maskPROPERTY, maskVALUEPut;
186 
187  pvd::PVDoublePtr displayLow, displayHigh, controlLow, controlHigh;
188  pvd::PVStringPtr egu, desc;
189  pvd::PVIntPtr fmt, prec;
190 
191  pvd::PVScalarPtr warnLow, warnHigh, alarmLow, alarmHigh;
192 
193  pvd::PVStringArrayPtr enumopts;
194 };
195 
196 struct pvScalar : public pvCommon {
197  typedef pvd::PVScalar pvd_type;
199 };
200 
201 struct pvArray : public pvCommon {
202  typedef pvd::PVScalarArray pvd_type;
204 };
205 
206 struct metaTIME {
207  DBRstatus
208  DBRtime
209 
210  enum {mask = DBR_STATUS | DBR_TIME};
211 };
212 
213 struct metaDOUBLE {
214  DBRstatus
215  DBRunits
216  DBRprecision
217  DBRtime
218  DBRgrDouble
219  DBRctrlDouble
220  DBRalDouble
221 
222  // similar junk
223  DBRenumStrs
224 
225  enum {mask = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_TIME | DBR_GR_DOUBLE | DBR_CTRL_DOUBLE | DBR_AL_DOUBLE};
226 };
227 
228 struct metaENUM {
229  DBRstatus
230  DBRtime
231  DBRenumStrs
232 
233  // similar junk
234  DBRunits
235  DBRprecision
236  DBRgrDouble
237  DBRctrlDouble
238  DBRalDouble
239 
240  enum {mask = DBR_STATUS | DBR_TIME | DBR_ENUM_STRS};
241 };
242 
243 struct metaSTRING {
244  DBRstatus
245  DBRtime
246 
247  // similar junk
248  DBRenumStrs
249  DBRunits
250  DBRprecision
251  DBRgrDouble
252  DBRctrlDouble
253  DBRalDouble
254 
255  enum {mask = DBR_STATUS | DBR_TIME};
256 };
257 
258 void attachTime(pvTimeAlarm& pvm, const pvd::PVStructurePtr& pv)
259 {
260 #define FMAP(MNAME, PVT, FNAME, DBE) pvm.MNAME = pv->getSubFieldT<pvd::PVT>(FNAME); \
261  pvm.mask ## DBE.set(pvm.MNAME->getFieldOffset())
262  FMAP(status, PVInt, "alarm.status", ALARM);
263  FMAP(severity, PVInt, "alarm.severity", ALARM);
264  FMAP(message, PVString, "alarm.message", ALARM);
265  FMAP(sec, PVLong, "timeStamp.secondsPastEpoch", ALWAYS);
266  FMAP(nsec, PVInt, "timeStamp.nanoseconds", ALWAYS);
267 #undef FMAP
268 }
269 
270 static
272 {
274  fmt.push_back("Default");
275  fmt.push_back("String");
276  fmt.push_back("Binary");
277  fmt.push_back("Decimal");
278  fmt.push_back("Hex");
279  fmt.push_back("Exponential");
280  fmt.push_back("Engineering");
281  return pvd::freeze(fmt);
282 }
283 
284 static const
285 pvd::shared_vector<const std::string> displayForms(buildFormats());
286 
287 // lookup fields and populate pvCommon. Non-existant fields will be NULL.
288 void attachMeta(pvCommon& pvm, const pvd::PVStructurePtr& pv)
289 {
290  {
291  pvd::PVStructurePtr fmt(pv->getSubField<pvd::PVStructure>("display.form"));
292  if(fmt) {
293  fmt->getSubFieldT<pvd::PVStringArray>("choices")->replace(displayForms);
294  }
295  }
296  attachTime(pvm, pv);
297 #define FMAP(MNAME, PVT, FNAME, DBE) pvm.MNAME = pv->getSubField<pvd::PVT>(FNAME); \
298  if(pvm.MNAME) pvm.mask ## DBE.set(pvm.MNAME->getFieldOffset())
299  FMAP(displayHigh, PVDouble, "display.limitHigh", PROPERTY);
300  FMAP(displayLow, PVDouble, "display.limitLow", PROPERTY);
301  FMAP(controlHigh, PVDouble, "control.limitHigh", PROPERTY);
302  FMAP(controlLow, PVDouble, "control.limitLow", PROPERTY);
303  FMAP(egu, PVString, "display.units", PROPERTY);
304  FMAP(desc, PVString, "display.description", PROPERTY);
305  FMAP(prec, PVInt, "display.precision", PROPERTY);
306  FMAP(fmt, PVInt, "display.form.index", PROPERTY);
307  FMAP(warnHigh, PVScalar, "valueAlarm.highWarningLimit", PROPERTY);
308  FMAP(warnLow, PVScalar, "valueAlarm.lowWarningLimit", PROPERTY);
309  FMAP(alarmHigh, PVScalar, "valueAlarm.highAlarmLimit", PROPERTY);
310  FMAP(alarmLow, PVScalar, "valueAlarm.lowAlarmLimit", PROPERTY);
311  FMAP(enumopts, PVStringArray, "value.choices", PROPERTY);
312 #undef FMAP
313 }
314 
315 template<typename PVX>
316 void attachAll(PVX& pvm, const pvd::PVStructurePtr& pv)
317 {
318  pvm.value = pv->getSubField<typename PVX::pvd_type>("value.index");
319  if(!pvm.value)
320  pvm.value = pv->getSubFieldT<typename PVX::pvd_type>("value");
321  const pvd::PVField *fld = pvm.value.get();
322  pvm.maskVALUE.set(fld->getFieldOffset());
323  for(;fld; fld = fld->getParent()) {
324  // set field bit and all enclosing structure bits
325  pvm.maskVALUEPut.set(fld->getFieldOffset());
326  }
327  pvm.maskVALUEPut.set(0);
328  attachMeta(pvm, pv);
329 }
330 
331 void mapStatus(unsigned code, pvd::PVInt* status, pvd::PVString* message)
332 {
333  if(code<ALARM_NSTATUS)
334  message->put(epicsAlarmConditionStrings[code]);
335  else
336  message->put("???");
337 
338  // Arbitrary mapping from DB status codes
339  unsigned out;
340  switch(code) {
341  case NO_ALARM:
342  out = 0;
343  break;
344  case READ_ALARM:
345  case WRITE_ALARM:
346  case HIHI_ALARM:
347  case HIGH_ALARM:
348  case LOLO_ALARM:
349  case LOW_ALARM:
350  case STATE_ALARM:
351  case COS_ALARM:
352  case HW_LIMIT_ALARM:
353  out = 1; // DEVICE
354  break;
355  case COMM_ALARM:
356  case TIMEOUT_ALARM:
357  case UDF_ALARM:
358  out = 2; // DRIVER
359  break;
360  case CALC_ALARM:
361  case SCAN_ALARM:
362  case LINK_ALARM:
363  case SOFT_ALARM:
364  case BAD_SUB_ALARM:
365  out = 3; // RECORD
366  break;
367  case DISABLE_ALARM:
368  case SIMM_ALARM:
369  case READ_ACCESS_ALARM:
370  case WRITE_ACCESS_ALARM:
371  out = 4; // DB
372  break;
373  default:
374  out = 6; // UNDEFINED
375  }
376 
377  status->put(out);
378 }
379 
380 
381 template<typename META>
382 void putMetaImpl(const pvTimeAlarm& pv, const META& meta)
383 {
384  pvd::int32 nsec = meta.time.nsec;
385  if(pv.nsecMask) {
386  pv.userTag->put(nsec&pv.nsecMask);
387  nsec &= ~pv.nsecMask;
388  }
389  pv.nsec->put(nsec); pv.sec->put(meta.time.secPastEpoch+POSIX_TIME_AT_EPICS_EPOCH);
390 }
391 
392 void putTime(const pvTimeAlarm& pv, unsigned dbe, db_field_log *pfl)
393 {
394  metaTIME meta;
395  long options = (int)metaTIME::mask, nReq = 0;
396 
397  long status = dbChannelGet(pv.chan, dbChannelFinalFieldType(pv.chan), &meta, &options, &nReq, pfl);
398  if(status)
399  throw std::runtime_error("dbGet for meta fails");
400 
401  putMetaImpl(pv, meta);
402  if(dbe&DBE_ALARM) {
403  mapStatus(meta.status, pv.status.get(), pv.message.get());
404  pv.severity->put(meta.severity);
405  }
406 }
407 
408 void putValue(dbChannel *chan, pvd::PVScalar* value, db_field_log *pfl)
409 {
410  dbrbuf buf;
411  long nReq = 1;
412 
413  long status = dbChannelGet(chan, dbChannelFinalFieldType(chan), &buf, NULL, &nReq, pfl);
414  if(status)
415  throw std::runtime_error("dbGet for meta fails");
416 
417  if(nReq==0) {
418  // this was an actual max length 1 array, which has zero elements now.
419  memset(&buf, 0, sizeof(buf));
420  }
421 
422  switch(dbChannelFinalFieldType(chan)) {
423 #define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case DBR_##DBFTYPE: value->putFrom<PVATYPE>(buf.dbf_##DBFTYPE); break;
424 #define CASE_ENUM
425 #define CASE_SKIP_BOOL
426 #include "pv/typemap.h"
427 #undef CASE_ENUM
428 #undef CASE_SKIP_BOOL
429 #undef CASE
430  case DBR_STRING:
431  buf.dbf_STRING[sizeof(buf.dbf_STRING)-1] = '\0';
432  value->putFrom<std::string>(buf.dbf_STRING);
433  break;
434  default:
435  throw std::runtime_error("putValue unsupported DBR code");
436  }
437 }
438 
439 void getValue(dbChannel *chan, pvd::PVScalar* value)
440 {
441  dbrbuf buf;
442 
443  switch(dbChannelFinalFieldType(chan)) {
444 #define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case DBR_##DBFTYPE: buf.dbf_##DBFTYPE = value->getAs<PVATYPE>(); break;
445 #define CASE_ENUM
446 #define CASE_SKIP_BOOL
447 #include "pv/typemap.h"
448 #undef CASE_ENUM
449 #undef CASE_SKIP_BOOL
450 #undef CASE
451  case DBR_STRING:
452  {
453  std::string val(value->getAs<std::string>());
454  strncpy(buf.dbf_STRING, val.c_str(), sizeof(buf.dbf_STRING));
455  buf.dbf_STRING[sizeof(buf.dbf_STRING)-1] = '\0';
456  }
457  break;
458  default:
459  throw std::runtime_error("getValue unsupported DBR code");
460  }
461 
462  long status = dbChannelPut(chan, dbChannelFinalFieldType(chan), &buf, 1);
463  if(status)
464  throw std::runtime_error("dbPut for meta fails");
465 }
466 
467 void getValue(dbChannel *chan, pvd::PVScalarArray* value)
468 {
469  short dbr = dbChannelFinalFieldType(chan);
470 
471  if(dbr!=DBR_STRING) {
473 
474  value->getAs(buf);
475  long nReq = buf.size()/pvd::ScalarTypeFunc::elementSize(value->getScalarArray()->getElementType());
476 
477  long status = dbChannelPut(chan, dbr, buf.data(), nReq);
478  if(status)
479  throw std::runtime_error("dbChannelPut fails");
480 
481  } else {
483 
484  value->getAs(buf);
485 
486  std::vector<char> temp(buf.size()*MAX_STRING_SIZE);
487 
488  for(size_t i=0, N=buf.size(); i<N; i++)
489  {
490  strncpy(&temp[i*MAX_STRING_SIZE], buf[i].c_str(), MAX_STRING_SIZE-1);
491  temp[i*MAX_STRING_SIZE + MAX_STRING_SIZE-1] = '\0';
492  }
493 
494  long status = dbChannelPut(chan, dbr, &temp[0], buf.size());
495  if(status)
496  throw std::runtime_error("dbChannelPut fails");
497  }
498 }
499 
500 void putValue(dbChannel *chan, pvd::PVScalarArray* value, db_field_log *pfl)
501 {
502  const short dbr = dbChannelFinalFieldType(chan);
503 
504  long nReq = dbChannelFinalElements(chan);
505  const pvd::ScalarType etype = value->getScalarArray()->getElementType();
506 
507  if(dbr!=DBR_STRING) {
508 
509  pvd::shared_vector<void> buf(pvd::ScalarTypeFunc::allocArray(etype, nReq)); // TODO: pool?
510 
511  long status = dbChannelGet(chan, dbr, buf.data(), NULL, &nReq, pfl);
512  if(status)
513  throw std::runtime_error("dbChannelGet for value fails");
514 
515  buf.slice(0, nReq*pvd::ScalarTypeFunc::elementSize(etype));
516 
517  value->putFrom(pvd::freeze(buf));
518 
519  } else {
520  std::vector<char> temp(nReq*MAX_STRING_SIZE);
521 
522  long status = dbChannelGet(chan, dbr, &temp[0], NULL, &nReq, pfl);
523  if(status)
524  throw std::runtime_error("dbChannelGet for value fails");
525 
527  for(long i=0; i<nReq; i++) {
528  temp[i*MAX_STRING_SIZE + MAX_STRING_SIZE-1] = '\0';
529  buf[i] = std::string(&temp[i*MAX_STRING_SIZE]);
530  }
531 
532  value->putFrom(pvd::freeze(buf));
533  }
534 }
535 template<typename META>
536 void putMeta(const pvCommon& pv, unsigned dbe, db_field_log *pfl)
537 {
538  META meta;
539  long options = (int)META::mask, nReq = 0;
540  dbCommon *prec = dbChannelRecord(pv.chan);
541 
542  long status = dbChannelGet(pv.chan, dbChannelFinalFieldType(pv.chan), &meta, &options, &nReq, pfl);
543  if(status)
544  throw std::runtime_error("dbGet for meta fails");
545 
546  putMetaImpl(pv, meta);
547 #define FMAP(MNAME, FNAME) pv.MNAME->put(meta.FNAME)
548  if(dbe&DBE_ALARM) {
549  mapStatus(meta.status, pv.status.get(), pv.message.get());
550  FMAP(severity, severity);
551  }
552  if(dbe&DBE_PROPERTY) {
553 #undef FMAP
554  if(pv.desc) pv.desc->put(prec->desc);
555 #define FMAP(MASK, MNAME, FNAME) if(META::mask&(MASK) && pv.MNAME) pv.MNAME->put(meta.FNAME)
556  FMAP(DBR_GR_DOUBLE, displayHigh, upper_disp_limit);
557  FMAP(DBR_GR_DOUBLE, displayLow, lower_disp_limit);
558  FMAP(DBR_CTRL_DOUBLE, controlHigh, upper_ctrl_limit);
559  FMAP(DBR_CTRL_DOUBLE, controlLow, lower_ctrl_limit);
560  FMAP(DBR_GR_DOUBLE, egu, units);
561 #undef FMAP
562  if(META::mask&DBR_PRECISION && pv.prec) {
563  pv.prec->put(pvd::int32(meta.precision.dp));
564  }
565 #define FMAP(MASK, MNAME, FNAME) if(META::mask&(MASK) && pv.MNAME) pv.MNAME->putFrom(meta.FNAME)
566  // not handling precision until I get a better idea of what 'format' is supposed to be...
567  //FMAP(prec, PVScalar, "display.form", PROPERTY);
568  FMAP(DBR_AL_DOUBLE, warnHigh, upper_warning_limit);
569  FMAP(DBR_AL_DOUBLE, warnLow, lower_warning_limit);
570  FMAP(DBR_AL_DOUBLE, alarmHigh, upper_alarm_limit);
571  FMAP(DBR_AL_DOUBLE, alarmLow, lower_alarm_limit);
572 #undef FMAP
573  if(pv.enumopts) {
574  pvd::shared_vector<std::string> strs(meta.no_str);
575  for(size_t i=0; i<strs.size(); i++)
576  {
577  meta.strs[i][sizeof(meta.strs[i])-1] = '\0';
578  strs[i] = meta.strs[i];
579  }
580  pv.enumopts->replace(pvd::freeze(strs));
581  }
582  }
583 }
584 
585 template<typename PVC, typename META>
586 void putAll(const PVC &pv, unsigned dbe, db_field_log *pfl)
587 {
588  if(dbe&(DBE_VALUE|DBE_ARCHIVE)) {
589  putValue(pv.chan, pv.value.get(), pfl);
590  }
591  if(!(dbe&DBE_PROPERTY)) {
592  putTime(pv, dbe, pfl);
593  } else {
594  putMeta<META>(pv, dbe, pfl);
595  }
596 }
597 
598 void findNSMask(pvTimeAlarm& pvmeta, pdbRecordIterator& info, const epics::pvData::PVStructurePtr& pvalue)
599 {
600  const char *UT = info.info("Q:time:tag");
601  if(UT && strncmp(UT, "nsec:lsb:", 9)==0) {
602  try{
603  pvmeta.nsecMask = epics::pvData::castUnsafe<pvd::uint32>(std::string(&UT[9]));
604  }catch(std::exception& e){
605  pvmeta.nsecMask = 0;
606  std::cerr<<info.name()<<" : Q:time:tag nsec:lsb: requires a number not '"<<UT[9]<<"'\n";
607  }
608  }
609  if(pvmeta.nsecMask>0 && pvmeta.nsecMask<=32) {
610  pvmeta.userTag = pvalue->getSubField<pvd::PVInt>("timeStamp.userTag");
611  if(!pvmeta.userTag) {
612  pvmeta.nsecMask = 0; // struct doesn't have userTag
613  } else {
614  pvd::uint64 mask = (1<<pvmeta.nsecMask)-1;
615  pvmeta.nsecMask = mask;
616  pvmeta.maskALWAYS.set(pvmeta.userTag->getFieldOffset());
617  }
618  } else
619  pvmeta.nsecMask = 0;
620 }
621 
622 void findFormat(pvTimeAlarm& pvmeta, pdbRecordIterator& info, const epics::pvData::PVStructurePtr& pvalue)
623 {
624  const char *FMT = info.info("Q:form");
625  if(FMT) {
626  pvd::PVScalarPtr fmt(pvalue->getSubField<pvd::PVScalar>("display.form.index"));
627  if(fmt) {
628  bool found = false;
629  for(size_t i=0; !found && i<displayForms.size(); i++) {
630  if((found=(displayForms[i]==FMT)))
631  fmt->putFrom<pvd::uint32>(i);
632  }
633  if(!found) {
634  try {
635  fmt->putFrom(std::string(FMT)); // attempt to parse as number
636  }catch(std::exception& e){
637  errlogPrintf("%s: info(Q:form, \"%s\") is not known format: %s\n", info.name(), FMT, e.what());
638  }
639  }
640  }
641  }
642 }
643 
644 
645 template<typename PVX, typename META>
646 struct PVIFScalarNumeric : public PVIF
647 {
648  PVX pvmeta;
649  const epics::pvData::PVStructurePtr pvalue;
650 
651  PVIFScalarNumeric(dbChannel *ch, const epics::pvData::PVFieldPtr& p, pvd::PVField *enclosing)
652  :PVIF(ch)
653  ,pvalue(std::tr1::dynamic_pointer_cast<pvd::PVStructure>(p))
654  {
655  if(!pvalue)
656  throw std::runtime_error("Must attach to structure");
657 
658  pvmeta.chan = ch;
659  attachAll<PVX>(pvmeta, pvalue);
660  if(enclosing) {
661  size_t bit = enclosing->getFieldOffset();
662  // we are inside a structure array or similar with only one bit for all ours fields
663  pvmeta.maskALWAYS.clear();
664  pvmeta.maskALWAYS.set(bit);
665  pvmeta.maskVALUE.clear();
666  pvmeta.maskVALUE.set(bit);
667  pvmeta.maskALARM.clear();
668  pvmeta.maskALARM.set(bit);
669  pvmeta.maskPROPERTY.clear();
670  pvmeta.maskPROPERTY.set(bit);
671  pvmeta.maskVALUEPut.clear();
672  pvmeta.maskVALUEPut.set(0);
673  pvmeta.maskVALUEPut.set(bit);
674  }
675  pdbRecordIterator info(chan);
676  findNSMask(pvmeta, info, pvalue);
677  findFormat(pvmeta, info, pvalue);
678  }
679  virtual ~PVIFScalarNumeric() {}
680 
681  virtual void put(epics::pvData::BitSet& mask, unsigned dbe, db_field_log *pfl) OVERRIDE FINAL
682  {
683  try{
684  putAll<PVX, META>(pvmeta, dbe, pfl);
685  mask |= pvmeta.maskALWAYS;
686  if(dbe&(DBE_VALUE|DBE_ARCHIVE))
687  mask |= pvmeta.maskVALUE;
688  if(dbe&DBE_ALARM)
689  mask |= pvmeta.maskALARM;
690  if(dbe&DBE_PROPERTY)
691  mask |= pvmeta.maskPROPERTY;
692  }catch(...){
693  pvmeta.severity->put(3);
694  mask |= pvmeta.maskALARM;
695  throw;
696  }
697  }
698 
699  virtual pvd::Status get(const epics::pvData::BitSet& mask, proc_t proc, bool permit) OVERRIDE FINAL
700  {
701  pvd::Status ret;
702  bool newval = mask.logical_and(pvmeta.maskVALUEPut);
703  if(newval) {
704  if(permit)
705  getValue(pvmeta.chan, pvmeta.value.get());
706  else
707  ret = pvd::Status::error("Put not permitted");
708  }
709  if(newval || proc==PVIF::ProcForce) {
710  if(permit)
711  ret = PVIF::get(mask, proc);
712  else
713  ret = pvd::Status::error("Process not permitted");
714  }
715  return ret;
716  }
717 
718  virtual unsigned dbe(const epics::pvData::BitSet& mask) OVERRIDE FINAL
719  {
720  unsigned ret = 0;
721  if(mask.logical_and(pvmeta.maskVALUE))
722  ret |= DBE_VALUE;
723  if(mask.logical_and(pvmeta.maskALARM))
724  ret |= DBE_ALARM;
725  if(mask.logical_and(pvmeta.maskPROPERTY))
726  ret |= DBE_PROPERTY;
727  return ret;
728  }
729 };
730 
731 } // namespace
732 
733 static
734 pvd::ScalarType DBR2PVD(short dbr)
735 {
736  switch(dbr) {
737 #define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case DBR_##DBFTYPE: return pvd::pv##PVACODE;
738 #define CASE_ENUM
739 #define CASE_SKIP_BOOL
740 #include "pv/typemap.h"
741 #undef CASE_ENUM
742 #undef CASE_SKIP_BOOL
743 #undef CASE
744  case DBF_STRING: return pvd::pvString;
745  }
746  throw std::invalid_argument("Unsupported DBR code");
747 }
748 
750 {
751  switch(pvt) {
752 #define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case pvd::pv##PVACODE: return DBR_##DBFTYPE;
753 #ifndef USE_INT64
754 # define CASE_SQUEEZE_INT64
755 #endif
756 #include "pv/typemap.h"
757 #ifndef USE_INT64
758 # undef CASE_SQUEEZE_INT64
759 #endif
760 #undef CASE
761  case pvd::pvString: return DBF_STRING;
762  }
763  return -1;
764 }
765 
767 ScalarBuilder::dtype(dbChannel *channel)
768 {
769  short dbr = dbChannelFinalFieldType(channel);
770  const long maxelem = dbChannelFinalElements(channel);
771  const pvd::ScalarType pvt = DBR2PVD(dbr);
772 
773  if(INVALID_DB_REQ(dbr))
774  throw std::invalid_argument("DBF code out of range");
775 
776  if(maxelem!=1 && dbr==DBR_ENUM)
777  dbr = DBF_SHORT;
778 
779  pvd::FieldBuilderPtr builder(pvd::getFieldCreate()->createFieldBuilder());
781 
782  if(dbr==DBR_ENUM)
783  builder = builder->setId("epics:nt/NTEnum:1.0")
784  ->addNestedStructure("value")
785  ->setId("enum_t")
786  ->add("index", pvd::pvInt)
787  ->addArray("choices", pvd::pvString)
788  ->endNested();
789  else if(maxelem==1)
790  builder = builder->setId("epics:nt/NTScalar:1.0")
791  ->add("value", pvt);
792  else
793  builder = builder->setId("epics:nt/NTScalarArray:1.0")
794  ->addArray("value", pvt);
795 
796  builder = builder->add("alarm", standard->alarm())
797  ->add("timeStamp", standard->timeStamp());
798 
799  if(dbr!=DBR_ENUM) {
800  builder = builder->addNestedStructure("display")
801  ->add("limitLow", pvd::pvDouble)
802  ->add("limitHigh", pvd::pvDouble)
803  ->add("description", pvd::pvString)
804  ->add("units", pvd::pvString)
805  ->add("precision", pvd::pvInt)
806  ->addNestedStructure("form")
807  ->setId("enum_t")
808  ->add("index", pvd::pvInt)
809  ->addArray("choices", pvd::pvString)
810  ->endNested()
811  ->endNested()
812  ->add("control", standard->control());
813 
814  if(dbr!=DBR_STRING)
815  builder = builder->add("valueAlarm", standard->doubleAlarm());
816  }
817 
818  return builder->createStructure();
819 }
820 
821 PVIF*
822 ScalarBuilder::attach(dbChannel *channel, const epics::pvData::PVStructurePtr& root, const FieldName& fldname)
823 {
824  if(!channel)
825  throw std::runtime_error("+type:\"scalar\" requires +channel:");
826  pvd::PVField *enclosing = 0;
827  pvd::PVFieldPtr fld(fldname.lookup(root, &enclosing));
828 
829  const short dbr = dbChannelFinalFieldType(channel);
830  const long maxelem = dbChannelFinalElements(channel);
831 
832  if(maxelem==1) {
833  switch(dbr) {
834  case DBR_CHAR:
835  case DBR_UCHAR:
836  case DBR_SHORT:
837  case DBR_USHORT:
838  case DBR_LONG:
839  case DBR_ULONG:
840 #ifdef USE_INT64
841  case DBR_INT64:
842  case DBR_UINT64:
843 #endif
844  return new PVIFScalarNumeric<pvScalar, metaDOUBLE>(channel, fld, enclosing);
845  case DBR_FLOAT:
846  case DBR_DOUBLE:
847  return new PVIFScalarNumeric<pvScalar, metaDOUBLE>(channel, fld, enclosing);
848  case DBR_ENUM:
849  return new PVIFScalarNumeric<pvScalar, metaENUM>(channel, fld, enclosing);
850  case DBR_STRING:
851  return new PVIFScalarNumeric<pvScalar, metaSTRING>(channel, fld, enclosing);
852  }
853  } else {
854  switch(dbr) {
855  case DBR_CHAR:
856  case DBR_UCHAR:
857  case DBR_SHORT:
858  case DBR_ENUM:
859  case DBR_USHORT:
860  case DBR_LONG:
861  case DBR_ULONG:
862  case DBR_STRING:
863  case DBR_FLOAT:
864 #ifdef USE_INT64
865  case DBR_INT64:
866  case DBR_UINT64:
867 #endif
868  case DBR_DOUBLE:
869  return new PVIFScalarNumeric<pvArray, metaDOUBLE>(channel, fld, enclosing);
870  }
871  }
872 
873  throw std::invalid_argument("Channel has invalid/unsupported DBR type");
874 }
875 
876 namespace {
877 template<class PVD>
878 struct PVIFPlain : public PVIF
879 {
880  const typename PVD::shared_pointer field;
881  size_t fieldOffset;
882  dbChannel * const channel;
883 
884  PVIFPlain(dbChannel *channel, const epics::pvData::PVFieldPtr& fld, epics::pvData::PVField* enclosing=0)
885  :PVIF(channel)
886  ,field(std::tr1::static_pointer_cast<PVD>(fld))
887  ,channel(channel)
888  {
889  if(!field)
890  throw std::logic_error("PVIFPlain attached type mis-match");
891  if(enclosing)
892  fieldOffset = enclosing->getFieldOffset();
893  else
894  fieldOffset = field->getFieldOffset();
895  }
896 
897  virtual ~PVIFPlain() {}
898 
899  virtual void put(epics::pvData::BitSet& mask, unsigned dbe, db_field_log *pfl) OVERRIDE FINAL
900  {
901  if(dbe&DBE_VALUE) {
902  putValue(channel, field.get(), pfl);
903  mask.set(fieldOffset);
904  }
905  }
906 
907  virtual pvd::Status get(const epics::pvData::BitSet& mask, proc_t proc, bool permit) OVERRIDE FINAL
908  {
909  pvd::Status ret;
910  bool newval = mask.get(fieldOffset);
911  if(newval) {
912  if(permit)
913  getValue(channel, field.get());
914  else
915  ret = pvd::Status::error("Put not permitted");
916  }
917  if(newval || proc==PVIF::ProcForce) {
918  if(permit)
919  ret = PVIF::get(mask, proc);
920  else
921  ret = pvd::Status::error("Process not permitted");
922  }
923  return ret;
924  }
925 
926  virtual unsigned dbe(const epics::pvData::BitSet& mask) OVERRIDE FINAL
927  {
928  // TODO: figure out how to handle various intermidiate compressed
929  // bitSet and enclosing.
930  // Until then check only also for wildcard bit (0).
931  if(mask.get(fieldOffset) || mask.get(0))
932  return DBE_VALUE;
933  return 0;
934  }
935 };
936 
937 struct PlainBuilder : public PVIFBuilder
938 {
939  virtual ~PlainBuilder() {}
940 
941  // fetch the structure description
942  virtual epics::pvData::FieldConstPtr dtype(dbChannel *channel) OVERRIDE FINAL {
943  const short dbr = dbChannelFinalFieldType(channel);
944  const long maxelem = dbChannelFinalElements(channel);
945  const pvd::ScalarType pvt = DBR2PVD(dbr);
946 
947  if(INVALID_DB_REQ(dbr))
948  throw std::invalid_argument("DBF code out of range");
949 
950  if(maxelem==1)
951  return pvd::getFieldCreate()->createScalar(pvt);
952  else
953  return pvd::getFieldCreate()->createScalarArray(pvt);
954  }
955 
956  // Attach to a structure instance.
957  // must be of the type returned by dtype().
958  // need not be the root structure
959  virtual PVIF* attach(dbChannel *channel,
960  const epics::pvData::PVStructurePtr& root,
961  const FieldName& fldname) OVERRIDE FINAL
962  {
963  if(!channel)
964  throw std::runtime_error("+type:\"plain\" requires +channel:");
965  const long maxelem = dbChannelFinalElements(channel);
966 
967  pvd::PVField *enclosing = 0;
968  pvd::PVFieldPtr fld(fldname.lookup(root, &enclosing));
969 
970  if(maxelem==1)
971  return new PVIFPlain<pvd::PVScalar>(channel, fld, enclosing);
972  else
973  return new PVIFPlain<pvd::PVScalarArray>(channel, fld, enclosing);
974  }
975 };
976 
977 struct AnyScalarBuilder : public PVIFBuilder
978 {
979  virtual ~AnyScalarBuilder() {}
980 
981  // fetch the structure description
982  virtual epics::pvData::FieldConstPtr dtype(dbChannel *channel) OVERRIDE FINAL {
983  (void)channel; //ignored
984  return pvd::getFieldCreate()->createVariantUnion();
985  }
986 
987  // Attach to a structure instance.
988  // must be of the type returned by dtype().
989  // need not be the root structure
990  virtual PVIF* attach(dbChannel *channel,
991  const epics::pvData::PVStructurePtr& root,
992  const FieldName& fldname) OVERRIDE FINAL
993  {
994  if(!channel)
995  throw std::runtime_error("+type:\"any\" requires +channel:");
997  const short dbr = dbChannelFinalFieldType(channel);
998  const long maxelem = dbChannelFinalElements(channel);
999  const pvd::ScalarType pvt = DBR2PVD(dbr);
1000 
1001  pvd::PVField *enclosing = 0;
1002  pvd::PVFieldPtr fld(fldname.lookup(root, &enclosing));
1003 
1004  pvd::PVUnion *value = dynamic_cast<pvd::PVUnion*>(fld.get());
1005  if(!value)
1006  throw std::logic_error("Mis-matched attachment point");
1007 
1008  pvd::PVFieldPtr arr(value->get());
1009  if(!arr) {
1010  if(maxelem==1)
1011  arr = create->createPVScalar(pvt);
1012  else
1013  arr = create->createPVScalarArray(pvt);
1014  value->set(arr);
1015  }
1016 
1017  if(maxelem==1)
1018  return new PVIFPlain<pvd::PVScalar>(channel, arr, enclosing ? enclosing : arr.get());
1019  else
1020  return new PVIFPlain<pvd::PVScalarArray>(channel, arr, enclosing ? enclosing : arr.get());
1021  }
1022 
1023 };
1024 
1025 struct PVIFMeta : public PVIF
1026 {
1027  pvTimeAlarm meta;
1028 
1029  PVIFMeta(dbChannel *channel, const epics::pvData::PVFieldPtr& fld, epics::pvData::PVField* enclosing=0)
1030  :PVIF(channel)
1031  {
1032  pvd::PVStructurePtr field(std::tr1::dynamic_pointer_cast<pvd::PVStructure>(fld));
1033  if(!field)
1034  throw std::logic_error("PVIFMeta attached type mis-match");
1035  meta.chan = channel;
1036  pdbRecordIterator info(chan);
1037  attachTime(meta, field);
1038  findNSMask(meta, info, field);
1039  findFormat(meta, info, field);
1040  if(enclosing) {
1041  meta.maskALWAYS.clear();
1042  meta.maskALWAYS.set(enclosing->getFieldOffset());
1043  meta.maskALARM.clear();
1044  meta.maskALARM.set(enclosing->getFieldOffset());
1045  }
1046  }
1047 
1048  virtual ~PVIFMeta() {}
1049 
1050  virtual void put(epics::pvData::BitSet& mask, unsigned dbe, db_field_log *pfl) OVERRIDE FINAL
1051  {
1052  mask |= meta.maskALWAYS;
1053  if(dbe&DBE_ALARM)
1054  mask |= meta.maskALARM;
1055 
1056  putTime(meta, dbe, pfl);
1057  }
1058 
1059  virtual pvd::Status get(const epics::pvData::BitSet& mask, proc_t proc, bool permit) OVERRIDE FINAL
1060  {
1061  // can't put time/alarm
1062  if(mask.logical_and(meta.maskALARM))
1063  return pvd::Status::warn("Put to meta field ignored");
1064  return pvd::Status::Ok;
1065  }
1066 
1067  virtual unsigned dbe(const epics::pvData::BitSet& mask) OVERRIDE FINAL
1068  {
1069  if(mask.logical_and(meta.maskALARM))
1070  return DBE_ALARM;
1071  return 0;
1072  }
1073 };
1074 
1075 struct MetaBuilder : public PVIFBuilder
1076 {
1077  virtual ~MetaBuilder() {}
1078 
1079  // fetch the structure description
1080  virtual epics::pvData::FieldConstPtr dtype(dbChannel *channel) OVERRIDE FINAL {
1081  throw std::logic_error("Don't call me");
1082  }
1083 
1085  const std::string& fld,
1086  dbChannel *channel)
1087  {
1089  if(fld.empty()) {
1090  return builder->add("alarm", std->alarm())
1091  ->add("timeStamp", std->timeStamp());
1092  } else {
1093  return builder->addNestedStructure(fld)
1094  ->add("alarm", std->alarm())
1095  ->add("timeStamp", std->timeStamp())
1096  ->endNested();
1097  }
1098  }
1099 
1100  // Attach to a structure instance.
1101  // must be of the type returned by dtype().
1102  // need not be the root structure
1103  virtual PVIF* attach(dbChannel *channel,
1104  const epics::pvData::PVStructurePtr& root,
1105  const FieldName& fldname) OVERRIDE FINAL
1106  {
1107  if(!channel)
1108  throw std::runtime_error("+type:\"meta\" requires +channel:");
1109 
1110  pvd::PVField *enclosing = 0;
1111  pvd::PVFieldPtr fld(fldname.lookup(root, &enclosing));
1112 
1113  return new PVIFMeta(channel, fld, enclosing);
1114  }
1115 
1116 };
1117 
1118 struct PVIFProc : public PVIF
1119 {
1120  PVIFProc(dbChannel *channel) :PVIF(channel) {}
1121 
1122  virtual void put(epics::pvData::BitSet& mask, unsigned dbe, db_field_log *pfl) OVERRIDE FINAL
1123  {
1124  // nothing to get
1125  }
1126 
1127  virtual pvd::Status get(const epics::pvData::BitSet& mask, proc_t proc, bool permit) OVERRIDE FINAL
1128  {
1129  // always process (if permitted)
1130  return PVIF::get(mask, PVIF::ProcForce, permit);
1131  }
1132 
1133  virtual unsigned dbe(const epics::pvData::BitSet& mask) OVERRIDE FINAL
1134  {
1135  return 0;
1136  }
1137 };
1138 
1139 struct ProcBuilder : public PVIFBuilder
1140 {
1141  // fetch the structure description
1142  virtual epics::pvData::FieldConstPtr dtype(dbChannel *channel) OVERRIDE FINAL {
1143  throw std::logic_error("Don't call me");
1144  }
1145 
1147  const std::string& fld,
1148  dbChannel *channel) OVERRIDE FINAL
1149  {
1150  // invisible
1151  return builder;
1152  }
1153  virtual PVIF* attach(dbChannel *channel,
1154  const epics::pvData::PVStructurePtr& root,
1155  const FieldName& fldname) OVERRIDE FINAL
1156  {
1157  if(!channel)
1158  throw std::runtime_error("+type:\"proc\" requires +channel:");
1159 
1160  return new PVIFProc(channel);
1161  }
1162 };
1163 
1164 }//namespace
1165 
1166 pvd::Status PVIF::get(const epics::pvData::BitSet& mask, proc_t proc, bool permit)
1167 {
1168  dbCommon *precord = dbChannelRecord(chan);
1169 
1170  bool tryproc = proc!=ProcPassive ? proc==ProcForce :
1171  dbChannelField(chan) == &precord->proc ||
1172  (dbChannelFldDes(chan)->process_passive &&
1173  precord->scan == 0);
1174 
1175  pvd::Status ret;
1176 
1177  if (tryproc) {
1178  if (!permit) {
1179  return pvd::Status::error("Process not permitted");
1180 
1181  } else if (precord->pact) {
1182  if (precord->tpro)
1183  printf("%s: Active %s\n",
1184  epicsThreadGetNameSelf(), precord->name);
1185  precord->rpro = TRUE;
1186  } else {
1187  /* indicate that dbPutField called dbProcess */
1188  precord->putf = TRUE;
1189  long err = dbProcess(precord);
1190  if(err) {
1191  char buf[32];
1192  errSymLookup(err, buf, sizeof(buf));
1193  std::ostringstream msg;
1194  msg<<"process error : "<<buf;
1195  ret = pvd::Status::error(msg.str());
1196  }
1197  }
1198  }
1199 
1200  return ret;
1201 }
1202 
1205  const std::string &fld,
1206  dbChannel *channel)
1207 {
1208  if(fld.empty())
1209  throw std::runtime_error("Can't attach this +type to root");
1210 
1211  epics::pvData::FieldConstPtr ftype(this->dtype(channel));
1212  if(ftype)
1213  builder = builder->add(fld, ftype);
1214 
1215  return builder;
1216 }
1217 
1219 {
1220  if(type.empty() || type=="scalar")
1221  return new ScalarBuilder;
1222  else if(type=="plain")
1223  return new PlainBuilder;
1224  else if(type=="any")
1225  return new AnyScalarBuilder;
1226  else if(type=="meta")
1227  return new MetaBuilder;
1228  else if(type=="proc")
1229  return new ProcBuilder;
1230  else
1231  throw std::runtime_error(std::string("Unknown +type=")+type);
1232 }
PVScalarValue< int32 > PVInt
Definition: pvData.h:496
PVIF(dbChannel *ch)
Definition: pvif.cpp:163
virtual epics::pvData::FieldConstPtr dtype(dbChannel *channel)=0
#define HIHI_ALARM
Definition: alarm.h:94
#define DBR_CHAR
Definition: db_access.h:74
static PVIFBuilder * create(const std::string &name)
Definition: pvif.cpp:1218
#define DBR_STRING
Definition: db_access.h:69
bool canWrite()
Definition: pvif.cpp:153
Definition: link.h:174
PVScalar is the base class for each scalar field.
Definition: pvData.h:272
static Status warn(const std::string &m)
Definition: status.h:49
std::tr1::shared_ptr< PVInt > PVIntPtr
Definition: pvData.h:507
virtual epics::pvData::FieldConstPtr dtype(dbChannel *channel) OVERRIDE FINAL
Definition: pvif.cpp:767
size_t elementSize(ScalarType id)
gives sizeof(T) where T depends on the scalar type id.
Definition: TypeFunc.cpp:82
pointer data() const
Return Base pointer.
Definition: sharedVector.h:616
#define READ_ALARM
Definition: alarm.h:92
virtual unsigned dbe(const epics::pvData::BitSet &mask)=0
Calculate DBE mask from changed bitset.
pvd::Status status
bool get(uint32 bitIndex) const
Definition: bitSet.cpp:130
#define asCheckPut(asClientPvt)
Definition: asLib.h:45
static Status Ok
Definition: status.h:47
static Status error(const std::string &m)
Definition: status.h:50
int i
Definition: scan.c:967
const char * info(const char *key, const char *def=0)
Definition: pvif.h:185
#define DBR_USHORT
Definition: dbFldTypes.h:80
Definition: tool_lib.h:67
LIBCOM_API long epicsStdCall asAddClient(ASCLIENTPVT *asClientPvt, ASMEMBERPVT asMemberPvt, int asl, const char *user, char *host)
std::vector< char > host
Definition: pvif.h:93
#define DBR_FLOAT
Definition: db_access.h:72
LIBCOM_API const char *epicsStdCall epicsThreadGetNameSelf(void)
Definition: osdThread.c:846
#define DBR_INT64
Definition: dbFldTypes.h:83
#define printf
Definition: epicsStdio.h:41
proc_t
Definition: pvif.h:361
dbChannel * chan
Definition: pvif.h:73
pvd::StructureConstPtr type
virtual void put(epics::pvData::BitSet &mask, unsigned dbe, db_field_log *pfl)=0
Definition: memory.hpp:41
#define INVALID_DB_REQ(x)
Definition: db_access.h:115
#define SOFT_ALARM
Definition: alarm.h:106
#define NULL
Definition: catime.c:38
A vector of bits.
Definition: bitSet.h:56
#define DBE_ALARM
Definition: caeventmask.h:41
void putFrom(T val)
Definition: pvData.h:324
PVField is the base class for each PVData field.
Definition: pvData.h:152
epicsTime begin
Definition: caConnTest.cpp:22
std::tr1::shared_ptr< PVLong > PVLongPtr
Definition: pvData.h:508
DBCH()
Definition: pvif.h:74
std::tr1::shared_ptr< PVStringArray > PVStringArrayPtr
Definition: pvData.h:1464
#define OVERRIDE
Definition: pvAccess.h:55
std::tr1::shared_ptr< FieldBuilder > FieldBuilderPtr
#define DBE_ARCHIVE
Definition: caeventmask.h:39
shared_vector< void > allocArray(ScalarType id, size_t len)
Allocate an untyped array based on ScalarType.
Definition: TypeFunc.cpp:104
#define DISABLE_ALARM
Definition: alarm.h:109
std::size_t getFieldOffset() const
Definition: PVField.cpp:44
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.
#define SCAN_ALARM
Definition: alarm.h:104
void swap(DBCH &)
Definition: pvif.cpp:67
#define DBR_UINT64
Definition: dbFldTypes.h:84
std::tr1::shared_ptr< StandardField > StandardFieldPtr
Definition: standardField.h:22
Definition: pvif.h:52
#define DBR_UCHAR
Definition: dbFldTypes.h:78
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
virtual epics::pvData::Status get(const epics::pvData::BitSet &mask, proc_t proc=ProcInhibit, bool permit=true)=0
Definition: pvif.cpp:1166
#define DBE_VALUE
Definition: caeventmask.h:38
std::vector< std::vector< char > > groups
Definition: pvif.h:94
uint64_t uint64
Definition: pvType.h:103
#define HIGH_ALARM
Definition: alarm.h:95
Holds all PVA related.
Definition: pvif.h:34
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()
void getAs(shared_vector< const T > &out) const
Definition: pvData.h:647
void add(dbChannel *chan, ASCred &cred)
Definition: pvif.cpp:139
pvData
Definition: monitor.h:428
#define CALC_ALARM
Definition: alarm.h:103
Definition: pvif.h:91
void push_back(param_type v)
Definition: sharedVector.h:602
LIBCOM_API void errSymLookup(long status, char *pBuf, size_t bufLength)
Definition: errSymLib.c:190
template class for all extensions of PVArray.
Definition: pvData.h:55
void update(const std::tr1::shared_ptr< epics::pvAccess::ChannelRequester > &request)
Definition: pvif.cpp:72
#define SIMM_ALARM
Definition: alarm.h:110
#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
#define DBR_GR_DOUBLE
Definition: db_access.h:100
#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
LIBCOM_API long epicsStdCall asRemoveClient(ASCLIENTPVT *asClientPvt)
bool logical_and(const BitSet &other) const
Returns true if any bit is set in both *this and other.
Definition: bitSet.cpp:214
#define POSIX_TIME_AT_EPICS_EPOCH
The EPICS Epoch is 00:00:00 Jan 1, 1990 UTC.
Definition: epicsTime.h:26
PVUnion has a single subfield.
Definition: pvData.h:940
Definition: sb.h:8
const ScalarArrayConstPtr getScalarArray() const
Data interface for a structure,.
Definition: pvData.h:712
std::tr1::shared_ptr< const Field > FieldConstPtr
Definition: pvIntrospect.h:137
#define LINK_ALARM
Definition: alarm.h:105
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
size_t size() const
Number of elements visible through this vector.
Definition: sharedVector.h:220
FORCE_INLINE const FieldCreatePtr & getFieldCreate()
epics::pvData::PVFieldPtr lookup(const epics::pvData::PVStructurePtr &S, epics::pvData::PVField **ppenclose) const
Definition: pdb.cpp:693
void put(typename storage_t::arg_type v)
Definition: pvData.h:401
PVScalarValue< int64 > PVLong
Definition: pvData.h:497
Definition: pvif.h:72
std::tr1::shared_ptr< PVStructure > PVStructurePtr
Definition: pvData.h:87
#define DBE_PROPERTY
Definition: caeventmask.h:42
#define BAD_SUB_ALARM
Definition: alarm.h:107
#define DBR_ENUM
Definition: db_access.h:73
std::tr1::shared_ptr< PVString > PVStringPtr
Definition: pvData.h:540
#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
std::tr1::shared_ptr< PVField > PVFieldPtr
Definition: pvData.h:66
#define TRUE
Definition: dbDefs.h:27
void putFrom(const shared_vector< const T > &inp)
Definition: pvData.h:666
PVValueArray< std::string > PVStringArray
Definition: pvData.h:1463
Definition: pvif.h:355
void swap(shared_ptr< T > &a, shared_ptr< T > &b) BOOST_NOEXCEPT
Definition: shared_ptr.hpp:783
#define STATE_ALARM
Definition: alarm.h:98
virtual PVIF * attach(dbChannel *channel, const epics::pvData::PVStructurePtr &root, const FieldName &fld) OVERRIDE FINAL
Definition: pvif.cpp:822
~ASCLIENT()
Definition: pvif.cpp:131
void slice(size_t offset, size_t length=(size_t)-1)
Reduce the view of this shared_vector.
Definition: sharedVector.h:244
~DBCH()
Definition: pvif.cpp:62
std::vector< char > user
Definition: pvif.h:93
BitSet & set(uint32 bitIndex)
Definition: bitSet.cpp:103
int prec
Definition: reader.c:29
dbChannel *const chan
Definition: pvif.h:359
std::tr1::shared_ptr< PVScalarArray > PVScalarArrayPtr
Definition: pvData.h:82
#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 FMAP(MNAME, PVT, FNAME, DBE)
#define WRITE_ACCESS_ALARM
Definition: alarm.h:112
#define LOW_ALARM
Definition: alarm.h:97
#define DBR_CTRL_DOUBLE
Definition: db_access.h:108
#define DBR_ULONG
Definition: dbFldTypes.h:82
PVScalarValue< double > PVDouble
Definition: pvData.h:503
const char * name() const
Definition: pvif.h:182
LIBCOM_API int asActive
Definition: asLibRoutines.c:40
T getAs() const
Definition: pvData.h:302
int32_t int32
Definition: pvType.h:83
#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
short PVD2DBR(pvd::ScalarType pvt)
Definition: pvif.cpp:749
#define FINAL
Definition: pvAccess.h:48
#define UDF_ALARM
Definition: alarm.h:108
uint32_t uint32
Definition: pvType.h:99
Exporting IOC objects.
#define WRITE_ALARM
Definition: alarm.h:93
char dbf_STRING[MAX_STRING_SIZE]
Definition: pvif.h:69