2 #include <epicsString.h>
5 #include <epicsStdio.h>
7 #include <pv/current_function.h>
14 using namespace pvalink;
16 #define TRY pvaLink *self = static_cast<pvaLink*>(plink->value.json.jlink); assert(self->alive); try
17 #define CATCH() catch(std::exception& e) { \
18 errlogPrintf("pvaLink %s fails %s: %s\n", CURRENT_FUNCTION, plink->precord->name, e.what()); \
21 #define CHECK_VALID() if(!self->valid()) { DEBUG(self, <<CURRENT_FUNCTION<<" "<<self->channelName<<" !valid"); return -1;}
23 dbfType getLinkType(DBLINK *plink)
25 dbCommon *prec = plink->precord;
28 for(
long status = dbFirstField(&iter.ent, 0); !status; status = dbNextField(&iter.ent, 0)) {
29 if(iter.ent.pfield==plink)
30 return iter.ent.pflddes->field_type;
32 throw std::logic_error(
"DBLINK* corrupt");
35 void pvaOpenLink(DBLINK *plink)
39 self->type = getLinkType(plink);
45 if(epicsStrCaseCmp(rec.info(
"base:lsetDebug",
"NO"),
"YES")==0) {
50 DEBUG(
self, <<plink->precord->name<<
" OPEN "<<self->channelName);
57 if(self->channelName.empty())
60 pvd::PVStructure::const_shared_pointer pvRequest(self->makeRequest());
61 pvaGlobal_t::channels_key_t key;
64 std::ostringstream strm;
67 key = std::make_pair(self->channelName, strm.str());
70 std::tr1::shared_ptr<pvaLinkChannel> chan;
73 Guard G(pvaGlobal->lock);
75 pvaGlobal_t::channels_t::iterator it(pvaGlobal->channels.find(key));
77 if(it!=pvaGlobal->channels.end()) {
79 chan = it->second.lock();
87 pvaGlobal->channels.insert(std::make_pair(key, chan));
91 doOpen &= pvaGlobal->running;
98 if(!self->local || chan->providerName==
"QSRV"){
101 chan->links.insert(
self);
102 chan->links_changed =
true;
104 self->lchan.swap(chan);
106 self->lchan->debug |= !!
self->debug;
109 fprintf(stderr,
"%s Error: local:true link to '%s' can't be fulfilled\n",
110 plink->precord->name, self->channelName.c_str());
120 void pvaRemoveLink(struct dbLocker *locker, DBLINK *plink)
123 p2p::auto_ptr<pvaLink>
self((
pvaLink*)plink->value.json.jlink);
124 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName);
130 int pvaIsConnected(
const DBLINK *plink)
133 Guard G(self->lchan->lock);
135 bool ret =
self->valid();
136 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" "<<ret);
143 int pvaGetDBFtype(const DBLINK *plink)
146 Guard G(self->lchan->lock);
154 pvd::PVField::const_shared_pointer value(self->getSubField(
"value"));
156 pvd::ScalarType ftype = pvd::pvInt;
159 }
else if(value->getField()->getType()==pvd::scalar)
160 ftype = static_cast<const pvd::Scalar*>(value->getField().get())->getScalarType();
161 else if(value->getField()->getType()==pvd::scalarArray)
162 ftype = static_cast<const pvd::ScalarArray*>(value->getField().get())->getElementType();
166 #define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case pvd::pv##PVACODE: ret = DBF_##DBFTYPE;
167 #define CASE_REAL_INT64
168 #include "pv/typemap.h"
169 #undef CASE_REAL_INT64
171 case pvd::pvString: ret = DBF_STRING;
174 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" "<<dbGetFieldTypeString(ret));
181 long pvaGetElements(const DBLINK *plink,
long *nelements)
184 Guard G(self->lchan->lock);
188 if(self->fld_value && self->fld_value->getField()->getType()==pvd::scalarArray)
189 ret = static_cast<const pvd::PVScalarArray*>(self->fld_value.get())->getLength();
191 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" "<<ret);
198 long pvaGetValue(DBLINK *plink,
short dbrType,
void *pbuffer,
202 Guard G(self->lchan->lock);
206 if(self->ms != pvaLink::NMS) {
207 recGblSetSevr(plink->precord, LINK_ALARM, self->snap_severity);
210 epicsTimeGetCurrent(&self->snap_time);
212 plink->precord->time =
self->snap_time;
214 DEBUG(
self, <<CURRENT_FUNCTION<<
" "<<self->channelName<<
" !valid");
218 if(self->fld_value) {
219 long status = copyPVD2DBF(self->fld_value, pbuffer, dbrType, pnRequest);
221 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" "<<status);
226 if(self->fld_seconds) {
227 self->snap_time.secPastEpoch =
self->fld_seconds->getAs<pvd::uint32>() - POSIX_TIME_AT_EPICS_EPOCH;
228 if(self->fld_nanoseconds) {
229 self->snap_time.nsec =
self->fld_nanoseconds->getAs<pvd::uint32>();
231 self->snap_time.nsec = 0u;
234 self->snap_time.secPastEpoch = 0u;
235 self->snap_time.nsec = 0u;
238 if(self->fld_severity) {
239 self->snap_severity =
self->fld_severity->getAs<pvd::uint16>();
241 self->snap_severity = NO_ALARM;
244 if((self->snap_severity!=NO_ALARM && self->ms == pvaLink::MS) ||
245 (
self->snap_severity==INVALID_ALARM &&
self->ms == pvaLink::MSI))
247 recGblSetSevr(plink->precord, LINK_ALARM, self->snap_severity);
251 plink->precord->time =
self->snap_time;
254 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" OK");
260 long pvaGetControlLimits(const DBLINK *plink,
double *lo,
double *hi)
263 Guard G(self->lchan->lock);
266 if(self->fld_control) {
267 pvd::PVScalar::const_shared_pointer value;
269 value = std::tr1::static_pointer_cast<
const pvd::PVScalar>(
self->fld_control->getSubField(
"limitLow"));
270 *lo = value ? value->getAs<
double>() : 0.0;
273 value = std::tr1::static_pointer_cast<
const pvd::PVScalar>(
self->fld_control->getSubField(
"limitHigh"));
274 *hi = value ? value->getAs<
double>() : 0.0;
279 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" "<<(lo ? *lo : 0)<<
" "<<(hi ? *hi : 0));
285 long pvaGetGraphicLimits(const DBLINK *plink,
double *lo,
double *hi)
288 Guard G(self->lchan->lock);
291 if(self->fld_display) {
292 pvd::PVScalar::const_shared_pointer value;
294 value = std::tr1::static_pointer_cast<
const pvd::PVScalar>(
self->fld_display->getSubField(
"limitLow"));
295 *lo = value ? value->getAs<
double>() : 0.0;
298 value = std::tr1::static_pointer_cast<
const pvd::PVScalar>(
self->fld_display->getSubField(
"limitHigh"));
299 *hi = value ? value->getAs<
double>() : 0.0;
304 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" "<<(lo ? *lo : 0)<<
" "<<(hi ? *hi : 0));
310 long pvaGetAlarmLimits(const DBLINK *plink,
double *lolo,
double *lo,
311 double *hi,
double *hihi)
316 *lolo = *lo = *hi = *hihi = 0.0;
317 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" "<<(lolo ? *lolo : 0)<<
" "<<(lo ? *lo : 0)<<
" "<<(hi ? *hi : 0)<<
" "<<(hihi ? *hihi : 0));
323 long pvaGetPrecision(const DBLINK *plink,
short *precision)
331 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" "<<precision);
337 long pvaGetUnits(const DBLINK *plink,
char *units,
int unitsSize)
340 Guard G(self->lchan->lock);
343 if(unitsSize==0)
return 0;
345 if(units && self->fld_display) {
346 pvd::PVString::const_shared_pointer value(std::tr1::static_pointer_cast<const pvd::PVString>(self->fld_display->getSubField(
"units")));
348 const std::string& egu = value->get();
349 strncpy(units, egu.c_str(), unitsSize);
354 units[unitsSize-1] =
'\0';
355 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" "<<units);
361 long pvaGetAlarm(const DBLINK *plink, epicsEnum16 *status,
362 epicsEnum16 *severity)
365 Guard G(self->lchan->lock);
369 *severity =
self->snap_severity;
372 *status =
self->snap_severity ? LINK_ALARM : NO_ALARM;
375 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" "<<(severity ? *severity : 0)<<
" "<<(status ? *status : 0));
381 long pvaGetTimeStamp(const DBLINK *plink, epicsTimeStamp *pstamp)
384 Guard G(self->lchan->lock);
388 *pstamp =
self->snap_time;
391 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" "<<(pstamp ? pstamp->secPastEpoch : 0)<<
":"<<(pstamp ? pstamp->nsec: 0));
398 pvd::ScalarType DBR2PVD(
short dbr)
401 #define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case DBR_##DBFTYPE: return pvd::pv##PVACODE;
402 #define CASE_SKIP_BOOL
403 #define CASE_REAL_INT64
404 #include "pv/typemap.h"
405 #undef CASE_SKIP_BOOL
406 #undef CASE_REAL_INT64
408 case DBF_ENUM:
return pvd::pvUShort;
409 case DBF_STRING:
return pvd::pvString;
411 throw std::invalid_argument(
"Unsupported DBR code");
414 long pvaPutValueX(DBLINK *plink,
short dbrType,
415 const void *pbuffer,
long nRequest,
bool wait)
419 Guard G(self->lchan->lock);
421 if(nRequest < 0)
return -1;
423 if(!self->retry && !self->valid()) {
424 DEBUG(
self, <<CURRENT_FUNCTION<<
" "<<self->channelName<<
" !valid");
428 pvd::ScalarType stype = DBR2PVD(dbrType);
430 pvd::shared_vector<const void> buf;
432 if(dbrType == DBF_STRING) {
433 const char *sbuffer = (
const char*)pbuffer;
434 pvd::shared_vector<std::string> sval(nRequest);
436 for(
long n=0; n<nRequest; n++, sbuffer += MAX_STRING_SIZE) {
437 sval[n] = std::string(sbuffer, epicsStrnLen(sbuffer, MAX_STRING_SIZE));
440 self->put_scratch = pvd::static_shared_vector_cast<
const void>(pvd::freeze(sval));
443 pvd::shared_vector<void> val(pvd::ScalarTypeFunc::allocArray(stype,
size_t(nRequest)));
445 assert(
size_t(dbValueSize(dbrType)*nRequest) == val.size());
447 memcpy(val.data(), pbuffer, val.size());
449 self->put_scratch = pvd::freeze(val);
452 self->used_scratch =
true;
456 self->lchan->after_put.insert(plink->precord);
459 if(!self->defer)
self->lchan->put();
461 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" "<<self->lchan->op_put.valid());
467 long pvaPutValue(DBLINK *plink,
short dbrType,
468 const
void *pbuffer,
long nRequest)
470 return pvaPutValueX(plink, dbrType, pbuffer, nRequest,
false);
473 long pvaPutValueAsync(DBLINK *plink,
short dbrType,
474 const void *pbuffer,
long nRequest)
476 return pvaPutValueX(plink, dbrType, pbuffer, nRequest,
true);
479 void pvaScanForward(DBLINK *plink)
482 Guard G(self->lchan->lock);
484 if(!self->retry && !self->valid()) {
489 self->lchan->put(
true);
491 DEBUG(
self, <<plink->precord->name<<
" "<<CURRENT_FUNCTION<<
" "<<self->channelName<<
" "<<self->lchan->op_put.valid());
511 &pvaGetControlLimits,
512 &pvaGetGraphicLimits,