pva2pva  1.4.1
 All Classes Functions Variables Pages
pvif.h
1 #ifndef PVIF_H
2 #define PVIF_H
3 
4 #include <map>
5 
6 #include <asLib.h>
7 #include <dbAccess.h>
8 #include <dbChannel.h>
9 #include <dbStaticLib.h>
10 #include <dbLock.h>
11 #include <dbEvent.h>
12 #include <epicsVersion.h>
13 
14 #include <pv/status.h>
15 #include <pv/bitSet.h>
16 #include <pv/pvData.h>
17 #include <pv/anyscalar.h>
18 
19 #include <pv/qsrv.h>
20 
21 #ifndef VERSION_INT
22 # define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
23 #endif
24 
25 #ifndef EPICS_VERSION_INT
26 # define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL)
27 #endif
28 
29 #if EPICS_VERSION_INT>=VERSION_INT(3,16,0,2)
30 # define USE_MULTILOCK
31 #endif
32 
33 #ifndef DBRutag
34 # define DBR_AMSG 0
35 # define DBR_UTAG 0
36 # define DBRamsg
37 # define DBRutag
38 #else
39 # define HAVE_UTAG
40 #endif
41 
42 namespace epics {
43 namespace pvAccess {
44 class ChannelRequester;
45 }
46 }
47 
48 short PVD2DBR(epics::pvData::ScalarType pvt);
49 
50 // copy from PVField (.value sub-field) to DBF buffer
51 QSRV_API
52 long copyPVD2DBF(const epics::pvData::PVField::const_shared_pointer& in,
53  void *outbuf, short outdbf, long *outnReq);
54 // copy from DBF buffer to PVField (.value sub-field)
55 QSRV_API
56 long copyDBF2PVD(const epics::pvData::shared_vector<const void>& buf,
57  const epics::pvData::PVField::shared_pointer& out,
58  epics::pvData::BitSet &changed,
59  const epics::pvData::PVStringArray::const_svector& choices);
60 
61 union dbrbuf {
62  epicsInt8 dbf_CHAR;
63  epicsUInt8 dbf_UCHAR;
64  epicsInt16 dbf_SHORT;
65  epicsUInt16 dbf_USHORT;
66  epicsEnum16 dbf_ENUM;
67  epicsInt32 dbf_LONG;
68  epicsUInt32 dbf_ULONG;
69  epicsFloat32 dbf_FLOAT;
70  epicsFloat64 dbf_DOUBLE;
71 
72 #ifdef EPICS_VERSION_INT
73 # if EPICS_VERSION_INT>=VERSION_INT(3,16,1,0)
74  epicsInt64 dbf_INT64;
75  epicsUInt64 dbf_UINT64;
76 # endif
77 #endif
78  char dbf_STRING[MAX_STRING_SIZE];
79 };
80 
81 struct QSRV_API DBCH {
82  dbChannel *chan;
83  DBCH() :chan(0) {}
84  explicit DBCH(dbChannel *ch); // calls dbChannelOpen()
85  explicit DBCH(const std::string& name);
86  ~DBCH();
87 
88  void swap(DBCH&);
89 
90  operator dbChannel*() { return chan; }
91  operator const dbChannel*() const { return chan; }
92  dbChannel *operator->() { return chan; }
93  const dbChannel *operator->() const { return chan; }
94 private:
95  DBCH(const DBCH&);
96  DBCH& operator=(const DBCH&);
97  void prepare();
98 };
99 
100 struct ASCred {
101  // string storage must be safely mutable. cf. asAddClient()
102  std::vector<char> user, host;
103  std::vector<std::vector<char> > groups;
104  void update(const std::tr1::shared_ptr<epics::pvAccess::ChannelRequester>& request);
105 };
106 
107 struct ASCLIENT {
108  ASCLIENTPVT aspvt;
109  std::vector<ASCLIENTPVT> grppvt;
110  ASCLIENT() :aspvt(0) {}
111  ~ASCLIENT();
112  // ASCred storage must remain valid
113  void add(dbChannel* chan, ASCred& cred);
114  bool canWrite();
115 };
116 
118  DBENTRY ent;
119  pdbRecordInfo(const char *name)
120  {
121  dbInitEntry(pdbbase, &ent);
122  if(dbFindRecordPart(&ent, &name))
123  throw std::runtime_error(ent.message);
124  }
125  ~pdbRecordInfo()
126  {
127  dbFinishEntry(&ent);
128  }
129  const char *info(const char *key, const char *def =0)
130  {
131  if(dbFindInfo(&ent, key))
132  return def;
133  return dbGetInfoString(&ent);
134  }
135 };
136 
138  DBENTRY ent;
139  bool m_done;
141  {
142  dbInitEntry(pdbbase, &ent);
143  m_done = dbFirstRecordType(&ent)!=0;
144  while(!m_done) {
145  if(dbFirstRecord(&ent)==0)
146  break;
147  // not instances of this type
148  m_done = dbNextRecordType(&ent)!=0;
149  }
150  }
151  pdbRecordIterator(const dbChannel *chan)
152  {
153 #if EPICS_VERSION_INT>=VERSION_INT(3,16,1,0)
154  dbInitEntryFromRecord(dbChannelRecord(chan), &ent);
155 #else
156  dbInitEntry(pdbbase, &ent);
157  if(dbFindRecord(&ent, dbChannelRecord(chan)->name)!=0)
158  throw std::logic_error("Record not found");
159 #endif
160  m_done = false;
161  }
162 #if EPICS_VERSION_INT>=VERSION_INT(3,16,1,0)
163  pdbRecordIterator(dbCommon *prec)
164  {
165  dbInitEntryFromRecord(prec, &ent);
166  m_done = false;
167  }
168 #endif
170  {
171  dbFinishEntry(&ent);
172  }
173  bool done() const { return m_done; }
174  bool next() {
175  if(!m_done && dbNextRecord(&ent)!=0)
176  {
177  // done with this recordType
178  while(true) {
179  m_done = dbNextRecordType(&ent)!=0;
180  if(m_done) break;
181  if(dbFirstRecord(&ent)==0)
182  break;
183  // not instances of this type
184  }
185  }
186  return m_done;
187  }
188  dbCommon* record() const {
189  return m_done ? NULL : (dbCommon*)ent.precnode->precord;
190  }
191  const char *name() const {
192  return m_done ? NULL : ent.precnode->recordname;
193  }
194  const char *info(const char *key, const char *def =0)
195  {
196  if(m_done || dbFindInfo(&ent, key))
197  return def;
198  return dbGetInfoString(&ent);
199  }
200 };
201 
203  DBENTRY ent;
204  bool m_done;
206  {
207  dbCopyEntryContents(&const_cast<pdbRecordIterator&>(I).ent, &ent);
208  m_done = dbFirstInfo(&ent)!=0;
209  }
210  ~pdbInfoIterator()
211  {
212  dbFinishEntry(&ent);
213  }
214  bool done() const { return m_done; }
215  bool next() {
216  m_done = dbNextInfo(&ent)!=0;
217  return m_done;
218  }
219  const char *name() { return dbGetInfoName(&ent); }
220  const char *value() { return dbGetInfoString(&ent); }
221 };
222 
223 struct DBEvent
224 {
225  dbEventSubscription subscript;
226  unsigned dbe_mask;
227  void *self;
228  unsigned index;
229  dbChannel *chan;
230  DBEvent() :subscript(NULL), self(NULL), index(0) {}
231  DBEvent(void* s) :subscript(NULL), self(s), index(0) {}
232  ~DBEvent() {destroy();}
233  void create(dbEventCtx ctx, dbChannel *ch, EVENTFUNC *fn, unsigned mask)
234  {
235  subscript = db_add_event(ctx, ch, fn, this, mask);
236  if(!subscript)
237  throw std::runtime_error("Failed to subscribe to dbEvent");
238  chan = ch;
239  dbe_mask = mask;
240  }
241  void destroy() {
242  if(subscript) db_cancel_event(subscript);
243  }
244  bool operator!() const { return !subscript; }
245 private:
246  DBEvent(const DBEvent&);
247  DBEvent& operator=(const DBEvent&);
248 };
249 
250 struct LocalFL
251 {
252  db_field_log *pfl;
253  bool ours;
254  LocalFL(db_field_log *pfl, dbChannel *pchan)
255  :pfl(pfl)
256  ,ours(false)
257  {
258  if(!pfl && (ellCount(&pchan->pre_chain)!=0 || ellCount(&pchan->post_chain)!=0)) {
259  pfl = db_create_read_log(pchan);
260  if(pfl) {
261  ours = true;
262  pfl = dbChannelRunPreChain(pchan, pfl);
263  if(pfl) pfl = dbChannelRunPostChain(pchan, pfl);
264  }
265  }
266  this->pfl = pfl;
267  }
268  ~LocalFL() {
269  if(ours) db_delete_field_log(pfl);
270  }
271 };
272 
274 {
275  dbCommon *prec;
276  DBScanLocker(dbChannel *chan) :prec(dbChannelRecord(chan))
277  { dbScanLock(prec); }
278  DBScanLocker(dbCommon *prec) :prec(prec)
279  { dbScanLock(prec); }
280  ~DBScanLocker()
281  { dbScanUnlock(prec); }
282 };
283 
284 #ifdef USE_MULTILOCK
285 
286 struct DBManyLock
287 {
288  dbLocker *plock;
289  DBManyLock() :plock(NULL) {}
290  DBManyLock(const std::vector<dbCommon*>& recs, unsigned flags=0)
291  :plock(dbLockerAlloc( (recs.size() > 0 ? (dbCommon**)&recs[0] : NULL), recs.size(), flags))
292  {
293  if(!plock) throw std::invalid_argument("Failed to create locker");
294  }
295  DBManyLock(dbCommon * const *precs, size_t nrecs, unsigned flags=0)
296  :plock(dbLockerAlloc((dbCommon**)precs, nrecs, flags))
297  {
298  if(!plock) throw std::invalid_argument("Failed to create locker");
299  }
300  ~DBManyLock() { if(plock) dbLockerFree(plock); }
301  void swap(DBManyLock& O) { std::swap(plock, O.plock); }
302  operator dbLocker*() { return plock; }
303 private:
304  DBManyLock(const DBManyLock&);
305  DBManyLock& operator=(const DBManyLock&);
306 };
307 
308 struct DBManyLocker
309 {
310  dbLocker *plock;
311  DBManyLocker(dbLocker *L) :plock(L)
312  {
313  dbScanLockMany(plock);
314  }
315  ~DBManyLocker()
316  {
317  dbScanUnlockMany(plock);
318  }
319 };
320 #endif
321 
322 struct QSRV_API FieldName
323 {
324  struct Component {
325  std::string name;
326  epicsUInt32 index;
327  Component() :index((epicsUInt32)-1) {}
328  Component(const std::string& name, epicsUInt32 index = (epicsUInt32)-1)
329  :name(name), index(index)
330  {}
331  bool isArray() const { return index!=(epicsUInt32)-1; }
332  };
333  typedef std::vector<Component> parts_t;
334  parts_t parts;
335 
336  FieldName() {}
337  explicit FieldName(const std::string&);
338 
339  void swap(FieldName& o) {
340  parts.swap(o.parts);
341  }
342 
343  bool empty() const { return parts.empty(); }
344  size_t size() const { return parts.size(); }
345  const Component& operator[](size_t i) const { return parts[i]; }
346  const Component& back() const { return parts.back(); }
347 
348  // Apply field name(s) to given structure
349  // if ppenclose!=NULL then the address of the enclosing field (eg. structureArray)
350  // whose fieldOffset shoulbe by used, or NULL if no enclosing
351  epics::pvData::PVFieldPtr
352  lookup(const epics::pvData::PVStructurePtr& S, epics::pvData::PVField** ppenclose) const;
353 
354  void show() const;
355 
356 #if !defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)
357 // Workaround needed for older GCC
358 private:
359 #endif
360  // Prevent default copy/assignment op's
361  FieldName(const FieldName&);
362  FieldName& operator=(const FieldName&);
363 };
364 
365 struct QSRV_API PVIF {
366  PVIF(dbChannel *ch);
367  virtual ~PVIF() {}
368 
369  dbChannel * const chan; // borrowed reference from PVIFBuilder
370 
371  enum proc_t {
372  ProcPassive,
373  ProcInhibit,
374  ProcForce,
375  };
376 
379  virtual void put(epics::pvData::BitSet& mask, unsigned dbe, db_field_log *pfl) =0;
382  virtual epics::pvData::Status get(const epics::pvData::BitSet& mask, proc_t proc=ProcInhibit, bool permit=true) =0;
384  virtual unsigned dbe(const epics::pvData::BitSet& mask) =0;
385 
386 private:
387  PVIF(const PVIF&);
388  PVIF& operator=(const PVIF&);
389 };
390 
403 struct QSRV_API PVIFBuilder
404 {
405  dbChannel* const channel;
406 
407  virtual ~PVIFBuilder() {}
408 
409  // fetch the structure description
410  virtual epics::pvData::FieldConstPtr dtype() =0;
411 
412  virtual epics::pvData::FieldBuilderPtr dtype(epics::pvData::FieldBuilderPtr& builder,
413  const std::string& fld);
414 
415  // Attach to a structure instance.
416  // must be of the type returned by dtype().
417  // must be the root structure
418  virtual PVIF* attach(const epics::pvData::PVStructurePtr& root, const FieldName& fld) =0;
419 
420  // entry point for Builder
421  static PVIFBuilder* create(const std::string& mapname, dbChannel* chan);
422 protected:
423  explicit PVIFBuilder(dbChannel* chan) : channel(chan) {}
424 private:
425  PVIFBuilder(const PVIFBuilder&);
426  PVIFBuilder& operator=(const PVIFBuilder&);
427 };
428 
429 struct QSRV_API ScalarBuilder : public PVIFBuilder
430 {
431  explicit ScalarBuilder(dbChannel* chan) :PVIFBuilder(chan) {}
432  virtual ~ScalarBuilder() {}
433 
434  virtual epics::pvData::FieldConstPtr dtype() OVERRIDE FINAL;
435  virtual PVIF* attach(const epics::pvData::PVStructurePtr& root, const FieldName& fld) OVERRIDE FINAL;
436 };
437 
438 
439 #endif // PVIF_H
Definition: pvif.h:107
Definition: pvif.h:81
Definition: pvif.h:100
Definition: pvif.h:365
Definition: pvif.h:61
Definition: pvif.h:223
Definition: pvif.h:250