pva2pva  1.4.1
 All Classes Functions Variables Pages
pvalink_link.cpp
1 #include <pv/reftrack.h>
2 #include <alarm.h>
3 
4 #include "pvalink.h"
5 
6 namespace pvalink {
7 
8 pvaLink::pvaLink()
9  :alive(true)
10  ,type((dbfType)-1)
11  ,plink(0)
12  ,used_scratch(false)
13  ,used_queue(false)
14 {
15  REFTRACE_INCREMENT(num_instances);
16 
17  snap_severity = INVALID_ALARM;
18  snap_time.secPastEpoch = 0;
19  snap_time.nsec = 0;
20 
21  //TODO: valgrind tells me these aren't initialized by Base, but probably should be.
22  parseDepth = 0;
23  parent = 0;
24 }
25 
26 pvaLink::~pvaLink()
27 {
28  alive = false;
29 
30  if(lchan) { // may be NULL if parsing fails
31  Guard G(lchan->lock);
32 
33  lchan->links.erase(this);
34  lchan->links_changed = true;
35 
36  bool new_debug = false;
37  for(pvaLinkChannel::links_t::const_iterator it(lchan->links.begin()), end(lchan->links.end())
38  ; it!=end; ++it)
39  {
40  const pvaLink *pval = *it;
41  if(pval->debug) {
42  new_debug = true;
43  break;
44  }
45  }
46 
47  lchan->debug = new_debug;
48  }
49 
50  REFTRACE_DECREMENT(num_instances);
51 }
52 
53 static
54 pvd::StructureConstPtr monitorRequestType = pvd::getFieldCreate()->createFieldBuilder()
55  ->addNestedStructure("field")
56  ->endNested()
57  ->addNestedStructure("record")
58  ->addNestedStructure("_options")
59  ->add("pipeline", pvd::pvBoolean)
60  ->add("atomic", pvd::pvBoolean)
61  ->add("queueSize", pvd::pvUInt)
62  ->endNested()
63  ->endNested()
64  ->createStructure();
65 
66 pvd::PVStructurePtr pvaLink::makeRequest()
67 {
68  pvd::PVStructurePtr ret(pvd::getPVDataCreate()->createPVStructure(monitorRequestType));
69  ret->getSubFieldT<pvd::PVBoolean>("record._options.pipeline")->put(pipeline);
70  ret->getSubFieldT<pvd::PVBoolean>("record._options.atomic")->put(true);
71  ret->getSubFieldT<pvd::PVUInt>("record._options.queueSize")->put(queueSize);
72  return ret;
73 }
74 
75 // caller must lock lchan->lock
76 bool pvaLink::valid() const
77 {
78  return lchan->connected_latched && lchan->op_mon.root;
79 }
80 
81 // caller must lock lchan->lock
82 pvd::PVField::const_shared_pointer pvaLink::getSubField(const char *name)
83 {
84  pvd::PVField::const_shared_pointer ret;
85  if(valid()) {
86  if(fieldName.empty()) {
87  // we access the top level struct
88  ret = lchan->op_mon.root->getSubField(name);
89 
90  } else {
91  // we access a sub-struct
92  ret = lchan->op_mon.root->getSubField(fieldName);
93  if(!ret) {
94  // noop
95  } else if(ret->getField()->getType()!=pvd::structure) {
96  // addressed sub-field isn't a sub-structure
97  if(strcmp(name, "value")!=0) {
98  // unless we are trying to fetch the "value", we fail here
99  ret.reset();
100  }
101  } else {
102  ret = static_cast<const pvd::PVStructure*>(ret.get())->getSubField(name);
103  }
104  }
105  }
106  return ret;
107 }
108 
109 // call with channel lock held
110 void pvaLink::onDisconnect()
111 {
112  DEBUG(this,<<plink->precord->name<<" disconnect");
113  // TODO: option to remain queue'd while disconnected
114 
115  used_queue = used_scratch = false;
116 }
117 
118 void pvaLink::onTypeChange()
119 {
120  DEBUG(this,<<plink->precord->name<<" type change");
121 
122  assert(lchan->connected_latched && !!lchan->op_mon.root); // we should only be called when connected
123 
124  fld_value = getSubField("value");
125  fld_seconds = std::tr1::dynamic_pointer_cast<const pvd::PVScalar>(getSubField("timeStamp.secondsPastEpoch"));
126  fld_nanoseconds = std::tr1::dynamic_pointer_cast<const pvd::PVScalar>(getSubField("timeStamp.nanoseconds"));
127  fld_severity = std::tr1::dynamic_pointer_cast<const pvd::PVScalar>(getSubField("alarm.severity"));
128  fld_display = std::tr1::dynamic_pointer_cast<const pvd::PVStructure>(getSubField("display"));
129  fld_control = std::tr1::dynamic_pointer_cast<const pvd::PVStructure>(getSubField("control"));
130  fld_valueAlarm = std::tr1::dynamic_pointer_cast<const pvd::PVStructure>(getSubField("valueAlarm"));
131 
132  proc_changed.clear();
133 
134  // build mask of all "changed" bits associated with our .value
135  // CP/CPP input links will process this link only for updates where
136  // the changed mask and proc_changed share at least one set bit.
137  if(fld_value) {
138  // bit for this field
139  proc_changed.set(fld_value->getFieldOffset());
140 
141  // bits of all parent fields
142  for(const pvd::PVStructure* parent = fld_value->getParent(); parent; parent = parent->getParent()) {
143  proc_changed.set(parent->getFieldOffset());
144  }
145 
146  if(fld_value->getField()->getType()==pvd::structure)
147  {
148  // bits of all child fields
149  const pvd::PVStructure *val = static_cast<const pvd::PVStructure*>(fld_value.get());
150  for(size_t i=val->getFieldOffset(), N=val->getNextFieldOffset(); i<N; i++)
151  proc_changed.set(i);
152  }
153  }
154 }
155 
156 } // namespace pvalink