This is Unofficial EPICS BASE Doxygen Site
pvaClientMonitor.cpp
Go to the documentation of this file.
1 /* pvaClientMonitor.cpp */
12 #include <sstream>
13 #include <pv/event.h>
14 #include <pv/bitSetUtil.h>
15 
16 #define epicsExportSharedSymbols
17 
18 #include <pv/pvaClient.h>
19 
20 using namespace epics::pvData;
21 using namespace epics::pvAccess;
22 using namespace std;
23 
24 namespace epics { namespace pvaClient {
25 
27 {
28  PvaClientMonitor::weak_pointer pvaClientMonitor;
29  PvaClient::weak_pointer pvaClient;
30 public:
32  PvaClientMonitorPtr const & pvaClientMonitor,
33  PvaClientPtr const &pvaClient)
34  : pvaClientMonitor(pvaClientMonitor),
35  pvaClient(pvaClient)
36  {}
38  if(PvaClient::getDebug()) std::cout << "~MonitorRequesterImpl" << std::endl;
39  }
40 
41  virtual std::string getRequesterName() {
42  PvaClientMonitorPtr clientMonitor(pvaClientMonitor.lock());
43  if(!clientMonitor) return string("pvaClientMonitor is null");
44  return clientMonitor->getRequesterName();
45  }
46 
47  virtual void message(std::string const & message, epics::pvData::MessageType messageType) {
48  PvaClientMonitorPtr clientMonitor(pvaClientMonitor.lock());
49  if(!clientMonitor) return;
50  clientMonitor->message(message,messageType);
51  }
52 
53  virtual void monitorConnect(
54  const Status& status,
55  Monitor::shared_pointer const & monitor,
56  Structure::const_shared_pointer const & structure)
57  {
58  PvaClientMonitorPtr clientMonitor(pvaClientMonitor.lock());
59  if(!clientMonitor) return;
60  clientMonitor->monitorConnect(status,monitor,structure);
61  }
62 
63  virtual void unlisten(epics::pvData::MonitorPtr const & monitor)
64  {
65  PvaClientMonitorPtr clientMonitor(pvaClientMonitor.lock());
66  if(!clientMonitor) return;
67  clientMonitor->unlisten(monitor);
68  }
69 
70  virtual void monitorEvent(epics::pvData::MonitorPtr const & monitor)
71  {
72  PvaClientMonitorPtr clientMonitor(pvaClientMonitor.lock());
73  if(!clientMonitor) return;
74  clientMonitor->monitorEvent(monitor);
75  }
76 };
77 
78 
79 PvaClientMonitorPtr PvaClientMonitor::create(
80  PvaClientPtr const &pvaClient,
81  PvaClientChannelPtr const & pvaClientChannel,
82  PVStructurePtr const &pvRequest)
83 {
84  PvaClientMonitorPtr clientMonitor(new PvaClientMonitor(pvaClient,pvaClientChannel,pvRequest));
85  clientMonitor->monitorRequester = MonitorRequesterImplPtr(
86  new MonitorRequesterImpl(clientMonitor,pvaClient));
87  return clientMonitor;
88 }
89 
90 PvaClientMonitorPtr PvaClientMonitor::create(
91  PvaClientPtr const &pvaClient,
92  std::string const & channelName,
93  std::string const & providerName,
94  std::string const & request,
95  PvaClientChannelStateChangeRequesterPtr const & stateChangeRequester,
96  PvaClientMonitorRequesterPtr const & monitorRequester)
97 {
98  if(PvaClient::getDebug()) {
99  cout<< "PvaClientMonitor::create(pvaClient,channelName,providerName,request,stateChangeRequester,monitorRequester)\n"
100  << " channelName " << channelName
101  << " providerName " << providerName
102  << " request " << request
103  << endl;
104  }
105  CreateRequest::shared_pointer createRequest(CreateRequest::create());
106  PVStructurePtr pvRequest(createRequest->createRequest(request));
107  if(!pvRequest) throw std::runtime_error(createRequest->getMessage());
108  PvaClientChannelPtr pvaClientChannel = pvaClient->createChannel(channelName,providerName);
109  PvaClientMonitorPtr clientMonitor(new PvaClientMonitor(pvaClient,pvaClientChannel,pvRequest));
110  clientMonitor->monitorRequester = MonitorRequesterImplPtr(
111  new MonitorRequesterImpl(clientMonitor,pvaClient));
112  if(stateChangeRequester) clientMonitor->pvaClientChannelStateChangeRequester = stateChangeRequester;
113  if(monitorRequester) clientMonitor->pvaClientMonitorRequester = monitorRequester;
114  pvaClientChannel->setStateChangeRequester(clientMonitor);
115  pvaClientChannel->issueConnect();
116  return clientMonitor;
117 }
118 
119 
120 PvaClientMonitor::PvaClientMonitor(
121  PvaClientPtr const &pvaClient,
122  PvaClientChannelPtr const & pvaClientChannel,
123  PVStructurePtr const &pvRequest)
124 : pvaClient(pvaClient),
125  pvaClientChannel(pvaClientChannel),
126  pvRequest(pvRequest),
127  isStarted(false),
128  connectState(connectIdle),
129  userPoll(false),
130  userWait(false)
131 {
132  if(PvaClient::getDebug()) {
133  cout<< "PvaClientMonitor::PvaClientMonitor\n"
134  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
135  << endl;
136  }
137 }
138 
139 PvaClientMonitor::~PvaClientMonitor()
140 {
141  if(PvaClient::getDebug()) {
142  cout<< "PvaClientMonitor::~PvaClientMonitor"
143  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
144  << endl;
145  }
146  if(monitor) {
147  if(isStarted) monitor->stop();
148  }
149 }
150 
151 void PvaClientMonitor::channelStateChange(PvaClientChannelPtr const & channel, bool isConnected)
152 {
153  if(PvaClient::getDebug()) {
154  cout<< "PvaClientMonitor::channelStateChange"
155  << " channelName " << channel->getChannelName()
156  << " isConnected " << (isConnected ? "true" : "false")
157  << endl;
158  }
159  if(isConnected&&!monitor)
160  {
161  connectState = connectActive;
162  monitor = pvaClientChannel->getChannel()->createMonitor(monitorRequester,pvRequest);
163  }
164  PvaClientChannelStateChangeRequesterPtr req(pvaClientChannelStateChangeRequester.lock());
165  if(req) {
166  req->channelStateChange(channel,isConnected);
167  }
168 }
169 
170 void PvaClientMonitor::event(PvaClientMonitorPtr const & monitor)
171 {
172  if(PvaClient::getDebug()) {
173  cout << "PvaClientMonitor::event"
174  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
175  << endl;
176  }
177  PvaClientMonitorRequesterPtr req(pvaClientMonitorRequester.lock());
178  if(req) req->event(monitor);
179 }
180 
181 void PvaClientMonitor::checkMonitorState()
182 {
183  if(PvaClient::getDebug()) {
184  cout << "PvaClientMonitor::checkMonitorState"
185  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
186  << " connectState " << connectState
187  << endl;
188  }
189  if(connectState==connectIdle) {
190  connect();
191  if(!isStarted) start();
192  return;
193  }
194  if(connectState==connectActive){
195  string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
196  + " "
197  + monitorConnectStatus.getMessage();
198  throw std::runtime_error(message);
199  }
200 }
201 
202 string PvaClientMonitor::getRequesterName()
203 {
204  PvaClientPtr yyy = pvaClient.lock();
205  if(!yyy) return string("PvaClientMonitor::getRequesterName() PvaClient isDestroyed");
206  return yyy->getRequesterName();
207 }
208 
209 void PvaClientMonitor::message(string const & message,MessageType messageType)
210 {
211  PvaClientPtr yyy = pvaClient.lock();
212  if(!yyy) return;
213  yyy->message(message, messageType);
214 }
215 
216 void PvaClientMonitor::monitorConnect(
217  const Status& status,
218  Monitor::shared_pointer const & monitor,
220 {
221  if(PvaClient::getDebug()) {
222  cout << "PvaClientMonitor::monitorConnect"
223  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
224  << " status.isOK " << (status.isOK() ? "true" : "false")
225  << endl;
226  }
227  {
228  Lock xx(mutex);
229  this->monitor = monitor;
230  if(!status.isOK()) {
231  stringstream ss;
232  ss << pvRequest;
233  string message = string("\nPvaClientMonitor::monitorConnect)")
234  + "\npvRequest\n" + ss.str()
235  + "\nerror\n" + status.getMessage();
236  monitorConnectStatus = Status(Status::STATUSTYPE_ERROR,message);
237  return;
238  }
239  }
240  bool signal = (connectState==connectWait) ? true : false;
241  monitorConnectStatus = status;
242  connectState = connected;
243  if(isStarted) {
244  if(PvaClient::getDebug()) {
245  cout << "PvaClientMonitor::monitorConnect"
246  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
247  << " is already started "
248  << endl;
249  }
250  return;
251  }
252  pvaClientData = PvaClientMonitorData::create(structure);
253  pvaClientData->setMessagePrefix(pvaClientChannel->getChannel()->getChannelName());
254  if(signal) {
255  if(PvaClient::getDebug()) {
256  cout << "PvaClientMonitor::monitorConnect calling waitForConnect.signal\n";
257  }
258  waitForConnect.signal();
259  if(PvaClient::getDebug()) {
260  cout << "PvaClientMonitor::monitorConnect calling start\n";
261  }
262  start();
263  } else {
264  if(PvaClient::getDebug()) {
265  cout << "PvaClientMonitor::monitorConnect calling start\n";
266  }
267  start();
268  }
269  PvaClientMonitorRequesterPtr req(pvaClientMonitorRequester.lock());
270  if(req) req->monitorConnect(status,shared_from_this(),structure);
271 }
272 
273 void PvaClientMonitor::monitorEvent(MonitorPtr const & monitor)
274 {
275  if(PvaClient::getDebug()) {
276  cout << "PvaClientMonitor::monitorEvent"
277  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
278  << endl;
279  }
280  PvaClientMonitorRequesterPtr req = pvaClientMonitorRequester.lock();
281  if(req) req->event(shared_from_this());
282  if(userWait) waitForEvent.signal();
283 }
284 
285 void PvaClientMonitor::unlisten(MonitorPtr const & monitor)
286 {
287  if(PvaClient::getDebug()) cout << "PvaClientMonitor::unlisten\n";
288  PvaClientMonitorRequesterPtr req = pvaClientMonitorRequester.lock();
289  if(req) {
290  req->unlisten();
291  return;
292  }
293  cerr << pvaClientChannel->getChannel()->getChannelName() + "pvaClientMonitor::unlisten called but no PvaClientMonitorRequester\n";
294 }
295 
296 
297 void PvaClientMonitor::connect()
298 {
299  if(PvaClient::getDebug()) cout << "PvaClientMonitor::connect\n";
300  issueConnect();
301  Status status = waitConnect();
302  if(status.isOK()) return;
303  string message = string("channel ")
304  + pvaClientChannel->getChannel()->getChannelName()
305  + " PvaClientMonitor::connect "
306  + status.getMessage();
307  throw std::runtime_error(message);
308 }
309 
310 void PvaClientMonitor::issueConnect()
311 {
312  if(PvaClient::getDebug()) cout << "PvaClientMonitor::issueConnect\n";
313  if(connectState!=connectIdle) {
314  string message = string("channel ")
315  + pvaClientChannel->getChannel()->getChannelName()
316  + " pvaClientMonitor already connected ";
317  throw std::runtime_error(message);
318  }
319  connectState = connectWait;
320  monitor = pvaClientChannel->getChannel()->createMonitor(monitorRequester,pvRequest);
321 }
322 
323 Status PvaClientMonitor::waitConnect()
324 {
325  if(PvaClient::getDebug()) {
326  cout << "PvaClientMonitor::waitConnect "
327  << pvaClientChannel->getChannel()->getChannelName()
328  << endl;
329  }
330  {
331  Lock xx(mutex);
332  if(connectState==connected) {
333  if(!monitorConnectStatus.isOK()) connectState = connectIdle;
334  return monitorConnectStatus;
335  }
336  if(connectState!=connectWait) {
337  string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
338  + " PvaClientMonitor::waitConnect illegal connect state ";
339  throw std::runtime_error(message);
340  }
341  }
342  waitForConnect.wait();
343  connectState = monitorConnectStatus.isOK() ? connected : connectIdle;
344  if(PvaClient::getDebug()) {
345  cout << "PvaClientMonitor::waitConnect"
346  << " monitorConnectStatus " << (monitorConnectStatus.isOK() ? "connected" : "not connected")
347  << endl;
348  }
349  return monitorConnectStatus;
350 }
351 
352 void PvaClientMonitor::setRequester(PvaClientMonitorRequesterPtr const & pvaClientMonitorRequester)
353 {
354  if(PvaClient::getDebug()) {
355  cout << "PvaClientMonitor::setRequester"
356  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
357  << endl;
358  }
359  this->pvaClientMonitorRequester = pvaClientMonitorRequester;
360 }
361 
362 void PvaClientMonitor::start()
363 {
364  if(PvaClient::getDebug()) {
365  cout << "PvaClientMonitor::start"
366  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
367  << " connectState " << connectState
368  << endl;
369  }
370  if(isStarted) {
371  return;
372  }
373  if(connectState==connectIdle) connect();
374  if(connectState!=connected) {
375  string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
376  + " PvaClientMonitor::start illegal state ";
377  throw std::runtime_error(message);
378  }
379  isStarted = true;
380  monitor->start();
381 }
382 
383 void PvaClientMonitor::start(string const & request)
384 {
385  if(PvaClient::getDebug()) {
386  cout<< "PvaMonitor::start(request)"
387  << " request " << request
388  << endl;
389  }
390  PvaClientPtr client(pvaClient.lock());
391  if(!client) throw std::runtime_error("pvaClient was deleted");
392  if(!pvaClientChannel->getChannel()->isConnected()) {
393  client->message(
394  "PvaClientMonitor::start(request) but not connected",
395  errorMessage);
396  return;
397  }
398  CreateRequest::shared_pointer createRequest(CreateRequest::create());
399  PVStructurePtr pvr(createRequest->createRequest(request));
400  if(!pvr) throw std::runtime_error(createRequest->getMessage());
401  if(monitor) {
402  if(isStarted) monitor->stop();
403  }
404  monitorRequester.reset();
405  monitor.reset();
406  isStarted = false;
407  connectState = connectIdle;
408  userPoll = false;
409  userWait = false;
410  monitorRequester = MonitorRequesterImplPtr(
411  new MonitorRequesterImpl(shared_from_this(),client));
412  pvRequest = pvr;
413  connect();
414 }
415 
416 
417 void PvaClientMonitor::stop()
418 {
419  if(PvaClient::getDebug()) {
420  cout << "PvaClientMonitor::stop"
421  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
422  << endl;
423  }
424  if(!isStarted) return;
425  isStarted = false;
426  monitor->stop();
427 }
428 
429 bool PvaClientMonitor::poll()
430 {
431  if(PvaClient::getDebug()) {
432  cout << "PvaClientMonitor::poll"
433  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
434  << endl;
435  }
436  checkMonitorState();
437  monitorElement = monitor->poll();
438  if(!monitorElement) return false;
439  userPoll = true;
440  pvaClientData->setData(monitorElement);
441  return true;
442 }
443 
444 bool PvaClientMonitor::waitEvent(double secondsToWait)
445 {
446  if(PvaClient::getDebug()) {
447  cout << "PvaClientMonitor::waitEvent"
448  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
449  << endl;
450  }
451  if(!isStarted) {
452  string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
453  + " PvaClientMonitor::waitEvent illegal state ";
454  throw std::runtime_error(message);
455  }
456  if(poll()) return true;
457  userWait = true;
458  if(secondsToWait==0.0) {
459  waitForEvent.wait();
460  } else {
461  waitForEvent.wait(secondsToWait);
462  }
463  userWait = false;
464  return poll();
465 }
466 
467 void PvaClientMonitor::releaseEvent()
468 {
469  if(PvaClient::getDebug()) {
470  cout << "PvaClientMonitor::releaseEvent"
471  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
472  << endl;
473  }
474  if(!userPoll) {
475  string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
476  + " PvaClientMonitor::releaseEvent did not call poll";
477  throw std::runtime_error(message);
478  }
479  userPoll = false;
480  monitor->release(monitorElement);
481 }
482 
483 PvaClientChannelPtr PvaClientMonitor::getPvaClientChannel()
484 {
485  return pvaClientChannel;
486 }
487 
488 PvaClientMonitorDataPtr PvaClientMonitor::getData()
489 {
490  if(PvaClient::getDebug()) {
491  cout << "PvaClientMonitor::getData"
492  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
493  << endl;
494  }
495  checkMonitorState();
496  return pvaClientData;
497 }
498 
499 
500 }}
std::tr1::shared_ptr< PvaClient > PvaClientPtr
Definition: pvaClient.h:46
std::string request
struct client client
pvd::Status status
static CreateRequest::shared_pointer create()
virtual void message(std::string const &message, epics::pvData::MessageType messageType)
virtual void monitorEvent(epics::pvData::MonitorPtr const &monitor)
std::tr1::shared_ptr< PvaClientMonitorData > PvaClientMonitorDataPtr
Definition: pvaClient.h:54
std::tr1::shared_ptr< PvaClientChannel > PvaClientChannelPtr
Definition: pvaClient.h:59
Definition: memory.hpp:41
TODO only here because of the Lockable.
Definition: ntaggregate.cpp:16
std::tr1::shared_ptr< const Structure > StructureConstPtr
Definition: pvIntrospect.h:162
A lock for multithreading.
Definition: lock.h:36
const std::string & getMessage() const
Definition: status.h:80
PVStructure::shared_pointer createRequest(std::string const &request)
Holds all PVA related.
Definition: pvif.h:34
pvData
Definition: monitor.h:428
Definition: server.h:76
std::tr1::shared_ptr< PvaClientMonitorRequester > PvaClientMonitorRequesterPtr
Definition: pvaClient.h:85
epicsMutex mutex
Definition: pvAccess.cpp:71
std::tr1::shared_ptr< PVStructure > PVStructurePtr
Definition: pvData.h:87
std::tr1::shared_ptr< MonitorRequesterImpl > MonitorRequesterImplPtr
Definition: pvaClient.h:1553
virtual void unlisten(epics::pvData::MonitorPtr const &monitor)
Callback implemented by monitor clients.
Definition: pvAccess.h:249
std::tr1::shared_ptr< PvaClientChannelStateChangeRequester > PvaClientChannelStateChangeRequesterPtr
Definition: pvaClient.h:56
virtual void monitorConnect(const Status &status, Monitor::shared_pointer const &monitor, Structure::const_shared_pointer const &structure)
bool isOK() const
Definition: status.h:95
An easy to use alternative to Monitor.
Definition: pvaClient.h:1561
MonitorRequesterImpl(PvaClientMonitorPtr const &pvaClientMonitor, PvaClientPtr const &pvaClient)
std::tr1::shared_ptr< PvaClientMonitor > PvaClientMonitorPtr
Definition: pvaClient.h:83
std::tr1::shared_ptr< Monitor > MonitorPtr
Definition: monitor.h:44