pvaClientCPP  4.8.1-dev
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 
26 class MonitorRequesterImpl : public MonitorRequester
27 {
28  PvaClientMonitor::weak_pointer pvaClientMonitor;
29  PvaClient::weak_pointer pvaClient;
30 public:
31  MonitorRequesterImpl(
32  PvaClientMonitorPtr const & pvaClientMonitor,
33  PvaClientPtr const &pvaClient)
34  : pvaClientMonitor(pvaClientMonitor),
35  pvaClient(pvaClient)
36  {}
37  virtual ~MonitorRequesterImpl() {
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, 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(MonitorPtr const & monitor)
64  {
65  PvaClientMonitorPtr clientMonitor(pvaClientMonitor.lock());
66  if(!clientMonitor) return;
67  clientMonitor->unlisten(monitor);
68  }
69 
70  virtual void monitorEvent(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  return pvaClientChannel->getRequesterName();
205 }
206 
207 void PvaClientMonitor::message(string const & message,MessageType messageType)
208 {
209  pvaClientChannel->message(message,messageType);
210 }
211 
212 void PvaClientMonitor::monitorConnect(
213  const Status& status,
214  Monitor::shared_pointer const & monitor,
215  StructureConstPtr const & structure)
216 {
217  if(PvaClient::getDebug()) {
218  cout << "PvaClientMonitor::monitorConnect"
219  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
220  << " status.isOK " << (status.isOK() ? "true" : "false")
221  << endl;
222  }
223  {
224  Lock xx(mutex);
225  monitorConnectStatus = status;
226  if(status.isOK()) {
227  this->monitor = monitor;
228  } else {
229  stringstream ss;
230  ss << pvRequest;
231  string message = string("\nPvaClientMonitor::monitorConnect)")
232  + "\nchannelName=" + pvaClientChannel->getChannel()->getChannelName()
233  + "\npvRequest\n" + ss.str()
234  + "\nerror\n" + status.getMessage();
235  monitorConnectStatus = Status(Status::STATUSTYPE_ERROR,message);
236  waitForConnect.signal();
237  PvaClientMonitorRequesterPtr req(pvaClientMonitorRequester.lock());
238  if(req) req->monitorConnect(status,shared_from_this(),structure);
239  return;
240  }
241  }
242  bool signal = (connectState==connectWait) ? true : false;
243  connectState = connected;
244  if(isStarted) {
245  if(PvaClient::getDebug()) {
246  cout << "PvaClientMonitor::monitorConnect"
247  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
248  << " is already started "
249  << endl;
250  }
251  waitForConnect.signal();
252  PvaClientMonitorRequesterPtr req(pvaClientMonitorRequester.lock());
253  if(req) req->monitorConnect(status,shared_from_this(),structure);
254  return;
255  }
256  pvaClientData = PvaClientMonitorData::create(structure);
257  pvaClientData->setMessagePrefix(pvaClientChannel->getChannel()->getChannelName());
258  if(signal) {
259  if(PvaClient::getDebug()) {
260  cout << "PvaClientMonitor::monitorConnect calling waitForConnect.signal\n";
261  }
262  waitForConnect.signal();
263  if(PvaClient::getDebug()) {
264  cout << "PvaClientMonitor::monitorConnect calling start\n";
265  }
266  start();
267  } else {
268  if(PvaClient::getDebug()) {
269  cout << "PvaClientMonitor::monitorConnect calling start\n";
270  }
271  start();
272  }
273  PvaClientMonitorRequesterPtr req(pvaClientMonitorRequester.lock());
274  if(req) req->monitorConnect(status,shared_from_this(),structure);
275 }
276 
277 void PvaClientMonitor::monitorEvent(MonitorPtr const & monitor)
278 {
279  if(PvaClient::getDebug()) {
280  cout << "PvaClientMonitor::monitorEvent"
281  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
282  << endl;
283  }
284  PvaClientMonitorRequesterPtr req = pvaClientMonitorRequester.lock();
285  if(req) req->event(shared_from_this());
286  if(userWait) waitForEvent.signal();
287 }
288 
289 void PvaClientMonitor::unlisten(MonitorPtr const & monitor)
290 {
291  if(PvaClient::getDebug()) cout << "PvaClientMonitor::unlisten\n";
292  PvaClientMonitorRequesterPtr req = pvaClientMonitorRequester.lock();
293  if(req) {
294  req->unlisten();
295  }
296 }
297 
298 
299 void PvaClientMonitor::connect()
300 {
301  if(PvaClient::getDebug()) cout << "PvaClientMonitor::connect\n";
302  issueConnect();
303  Status status = waitConnect();
304  if(status.isOK()) return;
305  string message = string("channel ")
306  + pvaClientChannel->getChannel()->getChannelName()
307  + " PvaClientMonitor::connect "
308  + status.getMessage();
309  throw std::runtime_error(message);
310 }
311 
312 void PvaClientMonitor::issueConnect()
313 {
314  if(PvaClient::getDebug()) cout << "PvaClientMonitor::issueConnect\n";
315  if(connectState!=connectIdle) {
316  string message = string("channel ")
317  + pvaClientChannel->getChannel()->getChannelName()
318  + " pvaClientMonitor already connected ";
319  throw std::runtime_error(message);
320  }
321  connectState = connectWait;
322  monitor = pvaClientChannel->getChannel()->createMonitor(monitorRequester,pvRequest);
323 }
324 
325 Status PvaClientMonitor::waitConnect()
326 {
327  if(PvaClient::getDebug()) {
328  cout << "PvaClientMonitor::waitConnect "
329  << pvaClientChannel->getChannel()->getChannelName()
330  << endl;
331  }
332  waitForConnect.wait();
333  if(PvaClient::getDebug()) {
334  cout << "PvaClientMonitor::waitConnect"
335  << " monitorConnectStatus " << (monitorConnectStatus.isOK() ? "connected" : "not connected")
336  << endl;
337  }
338  return monitorConnectStatus;
339 }
340 
341 void PvaClientMonitor::setRequester(PvaClientMonitorRequesterPtr const & pvaClientMonitorRequester)
342 {
343  if(PvaClient::getDebug()) {
344  cout << "PvaClientMonitor::setRequester"
345  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
346  << endl;
347  }
348  this->pvaClientMonitorRequester = pvaClientMonitorRequester;
349 }
350 
351 void PvaClientMonitor::start()
352 {
353  if(PvaClient::getDebug()) {
354  cout << "PvaClientMonitor::start"
355  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
356  << " connectState " << connectState
357  << endl;
358  }
359  if(isStarted) {
360  return;
361  }
362  if(connectState==connectIdle) connect();
363  if(connectState!=connected) {
364  string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
365  + " PvaClientMonitor::start illegal state ";
366  throw std::runtime_error(message);
367  }
368  isStarted = true;
369  monitor->start();
370 }
371 
372 void PvaClientMonitor::start(string const & request)
373 {
374  if(PvaClient::getDebug()) {
375  cout<< "PvaMonitor::start(request)"
376  << " request " << request
377  << endl;
378  }
379  PvaClientPtr client(pvaClient.lock());
380  if(!client) throw std::runtime_error("pvaClient was deleted");
381  if(!pvaClientChannel->getChannel()->isConnected()) {
382  client->message(
383  "PvaClientMonitor::start(request) but not connected",
384  errorMessage);
385  return;
386  }
387  CreateRequest::shared_pointer createRequest(CreateRequest::create());
388  PVStructurePtr pvr(createRequest->createRequest(request));
389  if(!pvr) throw std::runtime_error(createRequest->getMessage());
390  if(monitor) {
391  if(isStarted) monitor->stop();
392  }
393  monitorRequester.reset();
394  monitor.reset();
395  isStarted = false;
396  connectState = connectIdle;
397  userPoll = false;
398  userWait = false;
399  monitorRequester = MonitorRequesterImplPtr(
400  new MonitorRequesterImpl(shared_from_this(),client));
401  pvRequest = pvr;
402  connect();
403 }
404 
405 
406 void PvaClientMonitor::stop()
407 {
408  if(PvaClient::getDebug()) {
409  cout << "PvaClientMonitor::stop"
410  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
411  << endl;
412  }
413  if(!isStarted) return;
414  isStarted = false;
415  monitor->stop();
416 }
417 
418 bool PvaClientMonitor::poll()
419 {
420  if(PvaClient::getDebug()) {
421  cout << "PvaClientMonitor::poll"
422  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
423  << endl;
424  }
425  checkMonitorState();
426  monitorElement = monitor->poll();
427  if(!monitorElement) return false;
428  userPoll = true;
429  pvaClientData->setData(monitorElement);
430  return true;
431 }
432 
433 bool PvaClientMonitor::waitEvent(double secondsToWait)
434 {
435  if(PvaClient::getDebug()) {
436  cout << "PvaClientMonitor::waitEvent"
437  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
438  << endl;
439  }
440  if(!isStarted) {
441  string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
442  + " PvaClientMonitor::waitEvent illegal state ";
443  throw std::runtime_error(message);
444  }
445  if(poll()) return true;
446  userWait = true;
447  if(secondsToWait==0.0) {
448  waitForEvent.wait();
449  } else {
450  waitForEvent.wait(secondsToWait);
451  }
452  userWait = false;
453  return poll();
454 }
455 
456 void PvaClientMonitor::releaseEvent()
457 {
458  if(PvaClient::getDebug()) {
459  cout << "PvaClientMonitor::releaseEvent"
460  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
461  << endl;
462  }
463  if(!userPoll) {
464  string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
465  + " PvaClientMonitor::releaseEvent did not call poll";
466  throw std::runtime_error(message);
467  }
468  userPoll = false;
469  monitor->release(monitorElement);
470 }
471 
472 PvaClientChannelPtr PvaClientMonitor::getPvaClientChannel()
473 {
474  return pvaClientChannel;
475 }
476 
477 PvaClientMonitorDataPtr PvaClientMonitor::getData()
478 {
479  if(PvaClient::getDebug()) {
480  cout << "PvaClientMonitor::getData"
481  << " channelName " << pvaClientChannel->getChannel()->getChannelName()
482  << endl;
483  }
484  checkMonitorState();
485  return pvaClientData;
486 }
487 
488 
489 }}
std::tr1::shared_ptr< PvaClient > PvaClientPtr
Definition: pvaClient.h:46
std::tr1::shared_ptr< PvaClientMonitorData > PvaClientMonitorDataPtr
Definition: pvaClient.h:54
std::tr1::shared_ptr< PvaClientChannel > PvaClientChannelPtr
Definition: pvaClient.h:59
STL namespace.
std::tr1::shared_ptr< PvaClientMonitorRequester > PvaClientMonitorRequesterPtr
Definition: pvaClient.h:83
std::tr1::shared_ptr< MonitorRequesterImpl > MonitorRequesterImplPtr
Definition: pvaClient.h:1505
std::tr1::shared_ptr< PvaClientChannelStateChangeRequester > PvaClientChannelStateChangeRequesterPtr
Definition: pvaClient.h:56
An easy to use alternative to Monitor.
Definition: pvaClient.h:1512
std::tr1::shared_ptr< PvaClientMonitor > PvaClientMonitorPtr
Definition: pvaClient.h:81