pva2pva 1.4.2
Loading...
Searching...
No Matches
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
42namespace epics {
43namespace pvAccess {
44class ChannelRequester;
45}
46}
47
48short PVD2DBR(epics::pvData::ScalarType pvt);
49
50// copy from PVField (.value sub-field) to DBF buffer
51QSRV_API
52long 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)
55QSRV_API
56long 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
61union 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
81struct 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; }
94private:
95 DBCH(const DBCH&);
96 DBCH& operator=(const DBCH&);
97 void prepare();
98};
99
100struct 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
107struct 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
117struct pdbRecordInfo {
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
137struct pdbRecordIterator {
138 DBENTRY ent;
139 bool m_done;
140 pdbRecordIterator()
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
169 ~pdbRecordIterator()
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
202struct pdbInfoIterator {
203 DBENTRY ent;
204 bool m_done;
205 pdbInfoIterator(const pdbRecordIterator& I)
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
223struct 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; }
245private:
246 DBEvent(const DBEvent&);
247 DBEvent& operator=(const DBEvent&);
248};
249
250struct 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
273struct DBScanLocker
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
286struct 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; }
303private:
304 DBManyLock(const DBManyLock&);
305 DBManyLock& operator=(const DBManyLock&);
306};
307
308struct 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
322struct 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
358private:
359#endif
360 // Prevent default copy/assignment op's
361 FieldName(const FieldName&);
362 FieldName& operator=(const FieldName&);
363};
364
365struct 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
386private:
387 PVIF(const PVIF&);
388 PVIF& operator=(const PVIF&);
389};
390
403struct 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);
422protected:
423 explicit PVIFBuilder(dbChannel* chan) : channel(chan) {}
424private:
425 PVIFBuilder(const PVIFBuilder&);
426 PVIFBuilder& operator=(const PVIFBuilder&);
427};
428
429struct 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:100
Definition pvif.h:365
virtual void put(epics::pvData::BitSet &mask, unsigned dbe, db_field_log *pfl)=0
virtual unsigned dbe(const epics::pvData::BitSet &mask)=0
Calculate DBE mask from changed bitset.
virtual epics::pvData::Status get(const epics::pvData::BitSet &mask, proc_t proc=ProcInhibit, bool permit=true)=0
Definition pvif.cpp:1262
Definition pvif.h:61