This is Unofficial EPICS BASE Doxygen Site
pvaClientChannel.cpp
Go to the documentation of this file.
1 /* pvaClientChannel.cpp */
12 #include <map>
13 #include <pv/event.h>
14 #include <pv/lock.h>
15 #include <pv/createRequest.h>
16 
17 #define epicsExportSharedSymbols
18 
19 #include <pv/pvaClient.h>
20 
21 using namespace epics::pvData;
22 using namespace epics::pvAccess;
23 using namespace std;
24 
25 namespace epics { namespace pvaClient {
26 
27 
29 {
30 public:
33  {
34  if(PvaClient::getDebug()) cout << "PvaClientGetCache::~PvaClientGetCache\n";
35  }
36  PvaClientGetPtr getGet(string const & request);
37  void addGet(string const & request,PvaClientGetPtr const & pvaClientGet);
38  void showCache();
39  size_t cacheSize();
40 private:
41  map<string,PvaClientGetPtr> pvaClientGetMap;
42 };
43 
44 PvaClientGetPtr PvaClientGetCache::getGet(string const & request)
45 {
46  map<string,PvaClientGetPtr>::iterator iter = pvaClientGetMap.find(request);
47  if(iter!=pvaClientGetMap.end()) return iter->second;
48  return PvaClientGetPtr();
49 }
50 
51 void PvaClientGetCache::addGet(string const & request,PvaClientGetPtr const & pvaClientGet)
52 {
53  map<string,PvaClientGetPtr>::iterator iter = pvaClientGetMap.find(request);
54  if(iter!=pvaClientGetMap.end()) {
55  throw std::runtime_error("pvaClientGetCache::addGet pvaClientGet already cached");
56  }
57  pvaClientGetMap.insert(std::pair<string,PvaClientGetPtr>(request,pvaClientGet));
58 }
59 
60 void PvaClientGetCache::showCache()
61 {
62  map<string,PvaClientGetPtr>::iterator iter;
63  for(iter = pvaClientGetMap.begin(); iter != pvaClientGetMap.end(); ++iter)
64  {
65  cout << " " << iter->first << endl;
66  }
67 }
68 
69 size_t PvaClientGetCache::cacheSize()
70 {
71  return pvaClientGetMap.size();
72 
73 }
74 
76 {
77 public:
80  {
81  if(PvaClient::getDebug()) cout << "PvaClientPutCache::~PvaClientPutCache\n";
82  }
83  PvaClientPutPtr getPut(string const & request);
84  void addPut(string const & request,PvaClientPutPtr const & pvaClientPut);
85  void showCache();
86  size_t cacheSize();
87 private:
88  map<string,PvaClientPutPtr> pvaClientPutMap;
89 };
90 
91 
92 PvaClientPutPtr PvaClientPutCache::getPut(string const & request)
93 {
94  map<string,PvaClientPutPtr>::iterator iter = pvaClientPutMap.find(request);
95  if(iter!=pvaClientPutMap.end()) return iter->second;
96  return PvaClientPutPtr();
97 }
98 
99 void PvaClientPutCache::addPut(string const & request,PvaClientPutPtr const & pvaClientPut)
100 {
101  map<string,PvaClientPutPtr>::iterator iter = pvaClientPutMap.find(request);
102  if(iter!=pvaClientPutMap.end()) {
103  throw std::runtime_error("pvaClientPutCache::addPut pvaClientPut already cached");
104  }
105  pvaClientPutMap.insert(std::pair<string,PvaClientPutPtr>(
106  request,pvaClientPut));
107 }
108 
109 void PvaClientPutCache::showCache()
110 {
111  map<string,PvaClientPutPtr>::iterator iter;
112  for(iter = pvaClientPutMap.begin(); iter != pvaClientPutMap.end(); ++iter)
113  {
114  cout << " " << iter->first << endl;
115  }
116 }
117 
118 size_t PvaClientPutCache::cacheSize()
119 {
120  return pvaClientPutMap.size();
121 
122 }
123 
124 PvaClientChannelPtr PvaClientChannel::create(
125  PvaClientPtr const &pvaClient,
126  string const & channelName,
127  string const & providerName)
128 {
129  PvaClientChannelPtr channel(new PvaClientChannel(pvaClient,channelName,providerName));
130  return channel;
131 }
132 
133 
134 PvaClientChannel::PvaClientChannel(
135  PvaClientPtr const &pvaClient,
136  string const & channelName,
137  string const & providerName)
138 : pvaClient(pvaClient),
139  channelName(channelName),
140  providerName(providerName),
141  connectState(connectIdle),
143  pvaClientGetCache(new PvaClientGetCache()),
144  pvaClientPutCache(new PvaClientPutCache())
145 {
146  if(PvaClient::getDebug()) {
147  cout << "PvaClientChannel::PvaClientChannel channelName " << channelName << endl;
148  }
149 }
150 
151 PvaClientChannel::~PvaClientChannel()
152 {
153  if(PvaClient::getDebug()) {
154  cout << "PvaClientChannel::~PvaClientChannel() "
155  << " channelName " << channelName
156  << endl;
157  }
158  if(PvaClient::getDebug()) showCache();
159 }
160 
161 void PvaClientChannel::channelCreated(const Status& status, Channel::shared_pointer const & channel)
162 {
163  if(PvaClient::getDebug()) {
164  cout << "PvaClientChannel::channelCreated"
165  << " channelName " << channelName
166  << " connectState " << connectState
167  << " isConnected " << (channel->isConnected() ? "true" : "false")
168  << " status.isOK " << (status.isOK() ? "true" : "false")
169  << endl;
170  }
171  Lock xx(mutex);
172  this->channel = channel;
173  if(connectState==connected) return;
174  if(connectState!=connectActive) {
175  string message("PvaClientChannel::channelCreated");
176  message += " channel " + channelName
177  + " why was this called when connectState!=ConnectState.connectActive";
178  throw std::runtime_error(message);
179  }
180  if(!status.isOK()) {
181  string message("PvaClientChannel::channelCreated");
182  + " status " + status.getMessage() + " why??";
183  throw std::runtime_error(message);
184  }
185  if(channel->isConnected()) {
186  connectState = connected;
187  waitForConnect.signal();
188  }
189 }
190 
191 void PvaClientChannel::channelStateChange(
192  Channel::shared_pointer const & channel,
193  Channel::ConnectionState connectionState)
194 {
195  if(PvaClient::getDebug()) {
196  cout << " PvaClientChannel::channelStateChange "
197  << " channelName " << channelName
198  << " " << Channel::ConnectionStateNames[connectionState]
199  << endl;
200  }
201  bool waitingForConnect = false;
202  if(connectState==connectActive) waitingForConnect = true;
203  if(connectionState!=Channel::CONNECTED) {
204  Lock xx(mutex);
205  string mess(channelName +
206  " connection state " + Channel::ConnectionStateNames[connectionState]);
207  message(mess,errorMessage);
208  connectState = notConnected;
209  } else {
210  Lock xx(mutex);
211  this->channel = channel;
212  connectState = connected;
213  }
214  if(waitingForConnect) {
215  Lock xx(mutex);
216  waitForConnect.signal();
217  }
218  PvaClientChannelStateChangeRequesterPtr req(stateChangeRequester.lock());
219  if(req) {
220  bool value = (connectionState==Channel::CONNECTED ? true : false);
221  req->channelStateChange(shared_from_this(),value);
222  }
223 }
224 
225 string PvaClientChannel::getRequesterName()
226 {
227  PvaClientPtr yyy = pvaClient.lock();
228  if(!yyy) return string("PvaClientChannel::getRequesterName() PvaClient isDestroyed");
229  return yyy->getRequesterName();
230 }
231 
232 void PvaClientChannel::message(
233  string const & message,
234  MessageType messageType)
235 {
236  PvaClientPtr yyy = pvaClient.lock();
237  if(!yyy) return;
238  yyy->message(channelName + " " + message, messageType);
239 }
240 
241 string PvaClientChannel::getChannelName()
242 {
243  return channelName;
244 }
245 
246 Channel::shared_pointer PvaClientChannel::getChannel()
247 {
248  return channel;
249 }
250 
251 void PvaClientChannel::setStateChangeRequester(
252  PvaClientChannelStateChangeRequesterPtr const & stateChangeRequester)
253 {
254  this->stateChangeRequester = stateChangeRequester;
255  bool isConnected = false;
256  if(channel) isConnected = channel->isConnected();
257  stateChangeRequester->channelStateChange(shared_from_this(),isConnected);
258 }
259 
260 void PvaClientChannel::connect(double timeout)
261 {
262  if(PvaClient::getDebug()) {
263  cout << "PvaClientChannel::connect"
264  << " channelName " << channelName << endl;
265  }
266  issueConnect();
267  Status status = waitConnect(timeout);
268  if(status.isOK()) return;
269  if(PvaClient::getDebug()) cout << "PvaClientChannel::connect waitConnect failed\n";
270  string message = string("channel ") + channelName
271  + " PvaClientChannel::connect " + status.getMessage();
272  throw std::runtime_error(message);
273 }
274 
275 void PvaClientChannel::issueConnect()
276 {
277  if(PvaClient::getDebug()) {
278  cout << "PvaClientChannel::issueConnect"
279  << " channelName " << channelName << endl;
280  }
281  {
282  Lock xx(mutex);
283  if(connectState==connected) return;
284  if(connectState!=connectIdle) {
285  throw std::runtime_error("pvaClientChannel already connected");
286  }
287  connectState = connectActive;
288  }
289  ChannelProviderRegistry::shared_pointer reg(ChannelProviderRegistry::clients());
290  channelProvider = reg->getProvider(providerName);
291  if(!channelProvider) {
292  throw std::runtime_error(channelName + " provider " + providerName + " not registered");
293  }
294  if(PvaClient::getDebug()) cout << "PvaClientChannel::issueConnect calling provider->createChannel\n";
295  channel = channelProvider->createChannel(channelName,shared_from_this(),ChannelProvider::PRIORITY_DEFAULT);
296  if(!channel) {
297  throw std::runtime_error(channelName + " channelCreate failed ");
298  }
299 }
300 
301 Status PvaClientChannel::waitConnect(double timeout)
302 {
303  if(PvaClient::getDebug()) {
304  cout << "PvaClientChannel::waitConnect"
305  << " channelName " << channelName << endl;
306  }
307  {
308  Lock xx(mutex);
309  if(!channel) return Status(Status::STATUSTYPE_ERROR,"");
310  if(channel->isConnected()) return Status::Ok;
311  }
312  if(timeout>0.0) {
313  waitForConnect.wait(timeout);
314  } else {
315  waitForConnect.wait();
316  }
317  if(!channel) return Status(Status::STATUSTYPE_ERROR,"pvaClientChannel::waitConnect channel is null");
318  if(channel->isConnected()) return Status::Ok;
319  return Status(Status::STATUSTYPE_ERROR," not connected");
320 }
321 
322 
323 PvaClientFieldPtr PvaClientChannel::createField(string const & subField)
324 {
325  if(connectState!=connected) connect(5.0);
326  throw std::runtime_error("PvaClientChannel::createField not implemented");
327 }
328 
329 PvaClientProcessPtr PvaClientChannel::createProcess(string const & request)
330 {
331  PVStructurePtr pvRequest = createRequest->createRequest(request);
332  if(!pvRequest) {
333  string message = string("channel ") + channelName
334  + " PvaClientChannel::createProcess invalid pvRequest: "
335  + createRequest->getMessage();
336  throw std::runtime_error(message);
337  }
338  return createProcess(pvRequest);
339 }
340 
341 PvaClientProcessPtr PvaClientChannel::createProcess(PVStructurePtr const & pvRequest)
342 {
343  if(connectState!=connected) connect(5.0);
344  PvaClientPtr yyy = pvaClient.lock();
345  if(!yyy) throw std::runtime_error("PvaClient was destroyed");
346  return PvaClientProcess::create(yyy,shared_from_this(),pvRequest);
347 }
348 
349 
350 PvaClientGetPtr PvaClientChannel::get(string const & request)
351 {
352  PvaClientGetPtr pvaClientGet = pvaClientGetCache->getGet(request);
353  if(!pvaClientGet) {
354  pvaClientGet = createGet(request);
355  pvaClientGet->connect();
356  pvaClientGetCache->addGet(request,pvaClientGet);
357  }
358  pvaClientGet->get();
359  return pvaClientGet;
360 }
361 
362 
363 PvaClientGetPtr PvaClientChannel::createGet(string const & request)
364 {
365  PVStructurePtr pvRequest = createRequest->createRequest(request);
366  if(!pvRequest) {
367  string message = string("channel ") + channelName
368  + " PvaClientChannel::createGet invalid pvRequest: "
369  + createRequest->getMessage();
370  throw std::runtime_error(message);
371  }
372  return createGet(pvRequest);
373 }
374 
375 PvaClientGetPtr PvaClientChannel::createGet(PVStructurePtr const & pvRequest)
376 {
377  if(connectState!=connected) connect(5.0);
378  PvaClientPtr yyy = pvaClient.lock();
379  if(!yyy) throw std::runtime_error("PvaClient was destroyed");
380  return PvaClientGet::create(yyy,shared_from_this(),pvRequest);
381 }
382 
383 double PvaClientChannel::getDouble(string const & request)
384 {
385  return get(request)->getData()->getDouble();
386 }
387 
388 string PvaClientChannel::getString(string const & request)
389 {
390  return get(request)->getData()->getString();
391 }
392 
393 shared_vector<const double> PvaClientChannel::getDoubleArray(string const & request)
394 {
395  return get(request)->getData()->getDoubleArray();
396 }
397 
398 shared_vector<const std::string> PvaClientChannel::getStringArray(string const & request)
399 {
400  return get(request)->getData()->getStringArray();
401 }
402 
403 
404 PvaClientPutPtr PvaClientChannel::put(string const & request)
405 {
406  PvaClientPutPtr pvaClientPut = pvaClientPutCache->getPut(request);
407  if(pvaClientPut) return pvaClientPut;
408  if(!pvaClientPut) {
409  pvaClientPut = createPut(request);
410  pvaClientPut->connect();
411  pvaClientPut->get();
412  pvaClientPutCache->addPut(request,pvaClientPut);
413  }
414  return pvaClientPut;
415 }
416 
417 
418 PvaClientPutPtr PvaClientChannel::createPut(string const & request)
419 {
420  PVStructurePtr pvRequest = createRequest->createRequest(request);
421  if(!pvRequest) {
422  string message = string("channel ") + channelName
423  + " PvaClientChannel::createPut invalid pvRequest: "
424  + createRequest->getMessage();
425  throw std::runtime_error(message);
426  }
427  return createPut(pvRequest);
428 }
429 
430 PvaClientPutPtr PvaClientChannel::createPut(PVStructurePtr const & pvRequest)
431 {
432  if(connectState!=connected) connect(5.0);
433  PvaClientPtr yyy = pvaClient.lock();
434  if(!yyy) throw std::runtime_error("PvaClient was destroyed");
435  return PvaClientPut::create(yyy,shared_from_this(),pvRequest);
436 }
437 
438 void PvaClientChannel::putDouble(double value,string const & request)
439 {
440  PvaClientPutPtr clientPut = put(request);
441  PvaClientPutDataPtr putData = clientPut->getData();
442  putData->putDouble(value); clientPut->put();
443 }
444 
445 void PvaClientChannel::putString(std::string const & value,string const & request)
446 {
447  PvaClientPutPtr clientPut = put(request);
448  PvaClientPutDataPtr putData = clientPut->getData();
449  putData->putString(value); clientPut->put();
450 }
451 
452 void PvaClientChannel::putDoubleArray(
454  string const & request)
455 {
456  PvaClientPutPtr clientPut = put(request);
457  PvaClientPutDataPtr putData = clientPut->getData();
458  size_t n = value.size();
459  shared_vector<double> valueArray(n);
460  for(size_t i=0; i<n; ++i) valueArray[i] = value[i];
461  putData->putDoubleArray(freeze(valueArray)); clientPut->put();
462 }
463 
464 void PvaClientChannel::putStringArray(
466  string const & request)
467 {
468  PvaClientPutPtr clientPut = put(request);
469  PvaClientPutDataPtr putData = clientPut->getData();
470  size_t n = value.size();
471  shared_vector<string> valueArray(n);
472  for(size_t i=0; i<n; ++i) valueArray[i] = value[i];
473  putData->putStringArray(freeze(valueArray)); clientPut->put();
474 }
475 
476 PvaClientPutGetPtr PvaClientChannel::createPutGet(string const & request)
477 {
478  PVStructurePtr pvRequest = createRequest->createRequest(request);
479  if(!pvRequest) {
480  string message = string("channel ") + channelName
481  + " PvaClientChannel::createPutGet invalid pvRequest: "
482  + createRequest->getMessage();
483  throw std::runtime_error(message);
484  }
485  return createPutGet(pvRequest);
486 }
487 
488 PvaClientPutGetPtr PvaClientChannel::createPutGet(PVStructurePtr const & pvRequest)
489 {
490  if(connectState!=connected) connect(5.0);
491  PvaClientPtr yyy = pvaClient.lock();
492  if(!yyy) throw std::runtime_error("PvaClient was destroyed");
493  return PvaClientPutGet::create(yyy,shared_from_this(),pvRequest);
494 }
495 
496 
497 
498 PvaClientArrayPtr PvaClientChannel::createArray(string const & request)
499 {
500  PVStructurePtr pvRequest = createRequest->createRequest(request);
501  if(!pvRequest) {
502  string message = string("channel ") + channelName
503  + " PvaClientChannel::createArray invalid pvRequest: "
504  + createRequest->getMessage();
505  throw std::runtime_error(message);
506  }
507  return createArray(pvRequest);
508 }
509 
510 PvaClientArrayPtr PvaClientChannel::createArray(PVStructurePtr const & pvRequest)
511 {
512  if(connectState!=connected) connect(5.0);
513  throw std::runtime_error("PvaClientChannel::createArray not implemented");
514 }
515 
516 
517 PvaClientMonitorPtr PvaClientChannel::monitor(string const & request)
518 {
519  PvaClientMonitorPtr pvaClientMonitor = createMonitor(request);
520  pvaClientMonitor->connect();
521  pvaClientMonitor->start();
522  return pvaClientMonitor;
523 }
524 
525 PvaClientMonitorPtr PvaClientChannel::monitor(PvaClientMonitorRequesterPtr const & pvaClientMonitorRequester)
526 {
527  return monitor("field(value,alarm,timeStamp)",pvaClientMonitorRequester);
528 }
529 
530 PvaClientMonitorPtr PvaClientChannel::monitor(string const & request,
531  PvaClientMonitorRequesterPtr const & pvaClientMonitorRequester)
532 {
533  PvaClientMonitorPtr pvaClientMonitor = createMonitor(request);
534  pvaClientMonitor->connect();
535  pvaClientMonitor->setRequester(pvaClientMonitorRequester);
536  pvaClientMonitor->start();
537  return pvaClientMonitor;
538 }
539 
540 PvaClientMonitorPtr PvaClientChannel::createMonitor(string const & request)
541 {
542  PVStructurePtr pvRequest = createRequest->createRequest(request);
543  if(!pvRequest) {
544  string message = string("channel ") + channelName
545  + " PvaClientChannel::createMonitor invalid pvRequest: "
546  + createRequest->getMessage();
547  throw std::runtime_error(message);
548  }
549  return createMonitor(pvRequest);
550 }
551 
552 PvaClientMonitorPtr PvaClientChannel::createMonitor(PVStructurePtr const & pvRequest)
553 {
554  if(connectState!=connected) connect(5.0);
555  PvaClientPtr yyy = pvaClient.lock();
556  if(!yyy) throw std::runtime_error("PvaClient was destroyed");
557  return PvaClientMonitor::create(yyy,shared_from_this(),pvRequest);
558 }
559 
560 PVStructurePtr PvaClientChannel::rpc(
561  PVStructurePtr const & pvRequest,
562  PVStructurePtr const & pvArgument)
563 {
564 
565  PvaClientRPCPtr rpc = createRPC(pvRequest);
566  return rpc->request(pvArgument);
567 }
568 
569 PVStructurePtr PvaClientChannel::rpc(
570  PVStructurePtr const & pvArgument)
571 {
572  PvaClientRPCPtr rpc = createRPC();
573  return rpc->request(pvArgument);
574 }
575 
576 PvaClientRPCPtr PvaClientChannel::createRPC()
577 {
578  if(connectState!=connected) connect(5.0);
579  PvaClientPtr yyy = pvaClient.lock();
580  if(!yyy) throw std::runtime_error("PvaClient was destroyed");
581  return PvaClientRPC::create(yyy,channel);
582 }
583 
584 PvaClientRPCPtr PvaClientChannel::createRPC(PVStructurePtr const & pvRequest)
585 {
586  if(connectState!=connected) connect(5.0);
587  PvaClientPtr yyy = pvaClient.lock();
588  if(!yyy) throw std::runtime_error("PvaClient was destroyed");
589  return PvaClientRPC::create(yyy,channel,pvRequest);
590 }
591 
592 void PvaClientChannel::showCache()
593 {
594  if(pvaClientGetCache->cacheSize()>=1) {
595  cout << " pvaClientGet cache" << endl;
596  pvaClientGetCache->showCache();
597  } else {
598  cout << " pvaClientGet cache is empty\n";
599  }
600  if(pvaClientPutCache->cacheSize()>=1) {
601  cout << " pvaClientPut cache" << endl;
602  pvaClientPutCache->showCache();
603  } else {
604  cout << " pvaClientPut cache is empty\n";
605  }
606 }
607 
608 size_t PvaClientChannel::cacheSize()
609 {
610  return pvaClientGetCache->cacheSize() + pvaClientPutCache->cacheSize();
611 }
612 
613 
614 
615 }}
std::tr1::shared_ptr< PvaClient > PvaClientPtr
Definition: pvaClient.h:46
double timeout
Definition: pvutils.cpp:25
Definition: link.h:174
std::string request
std::tr1::shared_ptr< detail::SharedPut > put
A holder for a contiguous piece of memory.
Definition: sharedVector.h:27
pvd::Status status
static CreateRequest::shared_pointer create()
static Status Ok
Definition: status.h:47
int i
Definition: scan.c:967
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
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)
std::tr1::shared_ptr< PvaClientPut > PvaClientPutPtr
Definition: pvaClient.h:76
Holds all PVA related.
Definition: pvif.h:34
pvData
Definition: monitor.h:428
std::tr1::shared_ptr< PvaClientMonitorRequester > PvaClientMonitorRequesterPtr
Definition: pvaClient.h:85
epicsMutex mutex
Definition: pvAccess.cpp:71
std::tr1::shared_ptr< PvaClientArray > PvaClientArrayPtr
Definition: pvaClient.h:88
ChannelProviderRegistry::shared_pointer clients
#define epicsShareClass
Definition: shareLib.h:206
size_t size() const
Number of elements visible through this vector.
Definition: sharedVector.h:220
std::tr1::shared_ptr< PvaClientField > PvaClientFieldPtr
Definition: pvaClient.h:61
std::tr1::shared_ptr< PvaClientGet > PvaClientGetPtr
Definition: pvaClient.h:71
std::tr1::shared_ptr< PVStructure > PVStructurePtr
Definition: pvData.h:87
std::tr1::shared_ptr< PvaClientRPC > PvaClientRPCPtr
Definition: pvaClient.h:90
std::tr1::shared_ptr< PvaClientChannelStateChangeRequester > PvaClientChannelStateChangeRequesterPtr
Definition: pvaClient.h:56
An easy to use alternative to directly calling the Channel methods of pvAccess.
Definition: pvaClient.h:237
Definition: caget.c:48
std::tr1::shared_ptr< PvaClientProcess > PvaClientProcessPtr
Definition: pvaClient.h:66
std::tr1::shared_ptr< PvaClientPutGet > PvaClientPutGetPtr
Definition: pvaClient.h:81
bool isOK() const
Definition: status.h:95
std::tr1::shared_ptr< PvaClientMonitor > PvaClientMonitorPtr
Definition: pvaClient.h:83
std::tr1::shared_ptr< PvaClientPutData > PvaClientPutDataPtr
Definition: pvaClient.h:52