added enum string table cache to PV class
This commit is contained in:
@@ -344,6 +344,8 @@ public:
|
||||
|
||||
void postAccessRightsEvent ();
|
||||
|
||||
const vector<string> enumStringTable () const;
|
||||
|
||||
//
|
||||
// virtual functions
|
||||
//
|
||||
@@ -444,7 +446,10 @@ public:
|
||||
caStatus bestDBRType (unsigned &dbrType);
|
||||
|
||||
epicsShareFunc virtual casResType resourceType () const;
|
||||
|
||||
|
||||
const vector<string> enumStringTable () const;
|
||||
void updateEnumStringTable (unsigned nativeType);
|
||||
|
||||
//
|
||||
// virtual functions in the public interface class
|
||||
//
|
||||
@@ -465,6 +470,7 @@ public:
|
||||
|
||||
private:
|
||||
tsDLList<casPVListChan> chanList;
|
||||
vector<string> enumStrTbl;
|
||||
caServerI *pCAS;
|
||||
unsigned nMonAttached;
|
||||
unsigned nIOAttached;
|
||||
@@ -472,7 +478,6 @@ private:
|
||||
inline void lock () const;
|
||||
inline void unlock () const;
|
||||
|
||||
|
||||
epicsShareFunc virtual void destroy (); // casPVI destructor noop
|
||||
};
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gddAppTable.h" // EPICS application type table
|
||||
|
||||
#include "server.h"
|
||||
#include "casPVIIL.h" // casPVI inline func
|
||||
@@ -104,7 +105,6 @@ void casPVI::destroy ()
|
||||
//
|
||||
caStatus casPVI::attachToServer (caServerI &cas)
|
||||
{
|
||||
|
||||
if (this->pCAS) {
|
||||
//
|
||||
// currently we enforce that the PV can be attached to only
|
||||
@@ -115,6 +115,7 @@ caStatus casPVI::attachToServer (caServerI &cas)
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
//
|
||||
// install the PV into the server
|
||||
//
|
||||
@@ -124,6 +125,129 @@ caStatus casPVI::attachToServer (caServerI &cas)
|
||||
return S_cas_success;
|
||||
}
|
||||
|
||||
//
|
||||
// casPVI::updateEnumStringTable ()
|
||||
//
|
||||
// fetch string conversion table so that we can perform proper conversion
|
||||
// of enumerated PVs to strings during reads
|
||||
//
|
||||
// what a API complexity nightmare this GDD is
|
||||
//
|
||||
void casPVI::updateEnumStringTable (unsigned nativeType)
|
||||
{
|
||||
static const aitUint32 stringTableTypeStaticInit = 0xffffffff;
|
||||
static aitUint32 stringTableType = stringTableTypeStaticInit;
|
||||
caStatus status;
|
||||
gdd *pTmp;
|
||||
|
||||
//
|
||||
// reload the enum string table each time that the
|
||||
// PV is attached to the server
|
||||
//
|
||||
this->enumStrTbl.clear ();
|
||||
|
||||
//
|
||||
// empty string table for non-enumerated PVs
|
||||
//
|
||||
if (nativeType!=aitEnumEnum16) {
|
||||
this->enumStrTbl.clear ();
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// lazy init
|
||||
//
|
||||
if (stringTableType==stringTableTypeStaticInit) {
|
||||
stringTableType = gddApplicationTypeTable::app_table.registerApplicationType ("enums");
|
||||
}
|
||||
|
||||
//
|
||||
// create a gdd with the "enum string table" application type
|
||||
//
|
||||
pTmp = new gddScalar (stringTableType);
|
||||
if (pTmp==NULL) {
|
||||
errMessage (S_cas_noMemory, "unable to read application type \"enums\" string conversion table for enumerated PV");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// create a false context which is guaranteed to cause
|
||||
// any asynch IO to be ignored
|
||||
//
|
||||
casCtx ctx;
|
||||
|
||||
//
|
||||
// read the enum string table
|
||||
//
|
||||
status = this->read (ctx, *pTmp);
|
||||
if (status == S_casApp_asyncCompletion || status == S_casApp_postponeAsyncIO) {
|
||||
pTmp->unreference ();
|
||||
errMessage (status, " sorry, no support in server library for asynchronous completion of \"enums\" string conversion table for enumerated PV");
|
||||
errMessage (status, " please fetch \"enums\" string conversion table into cache during asychronous PV attach IO completion");
|
||||
return;
|
||||
}
|
||||
else if (status) {
|
||||
pTmp->unreference ();
|
||||
errMessage (status, "unable to read application type \"enums\" string conversion table for enumerated PV");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pTmp->isContainer()) {
|
||||
errMessage (S_cas_badType, "application type \"enums\" string conversion table for enumerated PV was a container (expected vector of strings)");
|
||||
pTmp->unreference ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (pTmp->dimension()==0) {
|
||||
if (pTmp->primitiveType()==aitEnumString) {
|
||||
aitString *pStr = (aitString *) pTmp->dataVoid ();
|
||||
this->enumStrTbl[0].assign (pStr->string());
|
||||
}
|
||||
else if (pTmp->primitiveType()==aitEnumFixedString) {
|
||||
aitFixedString *pStr = (aitFixedString *) pTmp->dataVoid ();
|
||||
this->enumStrTbl[0].assign (pStr->fixed_string);
|
||||
}
|
||||
else {
|
||||
errMessage (S_cas_badType, "application type \"enums\" string conversion table for enumerated PV isnt a string type?");
|
||||
}
|
||||
}
|
||||
else if (pTmp->dimension()==1) {
|
||||
gddStatus status;
|
||||
aitIndex index, first, count;
|
||||
|
||||
status = pTmp->getBound (0, first, count);
|
||||
assert (status == 0);
|
||||
|
||||
//
|
||||
// preallocate the correct amount
|
||||
//
|
||||
this->enumStrTbl.reserve (count);
|
||||
|
||||
if (pTmp->primitiveType()==aitEnumString) {
|
||||
aitString *pStr = (aitString *) pTmp->dataVoid ();
|
||||
for (index = 0; index<count; index++) {
|
||||
this->enumStrTbl[index].assign (pStr[index].string());
|
||||
}
|
||||
}
|
||||
else if (pTmp->primitiveType()==aitEnumFixedString) {
|
||||
aitFixedString *pStr = (aitFixedString *) pTmp->dataVoid ();
|
||||
for (index = 0; index<count; index++) {
|
||||
this->enumStrTbl[index].assign (pStr[index].fixed_string);
|
||||
}
|
||||
}
|
||||
else {
|
||||
errMessage (S_cas_badType, "application type \"enums\" string conversion table for enumerated PV isnt a string type?");
|
||||
}
|
||||
}
|
||||
else {
|
||||
errMessage (S_cas_badType, "application type \"enums\" string conversion table for enumerated PV was multi-dimensional (expected vector of strings)");
|
||||
}
|
||||
|
||||
pTmp->unreference ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// casPVI::registerEvent()
|
||||
//
|
||||
|
||||
@@ -198,6 +198,14 @@ inline aitIndex casPVI::nativeCount ()
|
||||
return this->maxBound(0u);
|
||||
}
|
||||
|
||||
//
|
||||
// casPVI::enumStringTable ()
|
||||
//
|
||||
inline const vector<string> casPVI::enumStringTable () const
|
||||
{
|
||||
return this->enumStrTbl;
|
||||
}
|
||||
|
||||
#endif // casPVIIL_h
|
||||
|
||||
|
||||
|
||||
@@ -109,6 +109,31 @@ casStrmClient::~casStrmClient()
|
||||
this->unlock();
|
||||
}
|
||||
|
||||
//
|
||||
// casStrmClient::uknownMessageAction()
|
||||
//
|
||||
caStatus casStrmClient::uknownMessageAction ()
|
||||
{
|
||||
const caHdr *mp = this->ctx.getMsg();
|
||||
caStatus status;
|
||||
|
||||
ca_printf ("CAS: bad request code from virtual circuit=%u\n", mp->m_cmmd);
|
||||
this->dumpMsg (mp, this->ctx.getData());
|
||||
|
||||
/*
|
||||
* most clients dont recover from this
|
||||
*/
|
||||
status = this->sendErr (mp, ECA_INTERNAL, "Invalid Request Code");
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* returning S_cas_internal here disconnects
|
||||
* the client with the bad message
|
||||
*/
|
||||
return S_cas_internal;
|
||||
}
|
||||
|
||||
//
|
||||
// casStrmClient::verifyRequest()
|
||||
@@ -171,7 +196,6 @@ void casStrmClient::show (unsigned level) const
|
||||
this->outBuf::show(level);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* casStrmClient::readAction()
|
||||
*/
|
||||
@@ -215,7 +239,7 @@ caStatus casStrmClient::readAction ()
|
||||
pChan->getPVI().addItemToIOBLockedList(*this);
|
||||
}
|
||||
else {
|
||||
status = this->sendErrWithEpicsStatus(mp, status, ECA_GETFAIL);
|
||||
status = this->sendErrWithEpicsStatus (mp, status, ECA_GETFAIL);
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -257,7 +281,7 @@ caStatus casStrmClient::readResponse (casChannelI *pChan, const caHdr &msg,
|
||||
// convert gdd to db_access type
|
||||
// (places the data in network format)
|
||||
//
|
||||
mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr((reply+1), msg.m_count, desc);
|
||||
mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr((reply+1), msg.m_count, desc, pChan->enumStringTable());
|
||||
if (mapDBRStatus<0) {
|
||||
desc.dump();
|
||||
errPrintf (S_cas_badBounds, __FILE__, __LINE__, "- get with PV=%s type=%u count=%u",
|
||||
@@ -419,7 +443,7 @@ caStatus casStrmClient::readNotifyResponseECA_XXX (casChannelI *pChan,
|
||||
// convert gdd to db_access type
|
||||
// (places the data in network format)
|
||||
//
|
||||
mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr((reply+1), msg.m_count, *pDesc);
|
||||
mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr((reply+1), msg.m_count, *pDesc, pChan->enumStringTable());
|
||||
if (mapDBRStatus<0) {
|
||||
pDesc->dump();
|
||||
errPrintf (S_cas_badBounds, __FILE__, __LINE__, "- get notify with PV=%s type=%u count=%u",
|
||||
@@ -555,7 +579,7 @@ caStatus casStrmClient::monitorResponse(casChannelI &chan, const caHdr &msg,
|
||||
// there appears to be no success/fail
|
||||
// status from this routine
|
||||
//
|
||||
gddMapDbr[msg.m_dataType].conv_dbr ((pReply+1), msg.m_count, *pDBRDD);
|
||||
gddMapDbr[msg.m_dataType].conv_dbr ((pReply+1), msg.m_count, *pDBRDD, chan.enumStringTable());
|
||||
|
||||
#ifdef CONVERSION_REQUIRED
|
||||
/* use type as index into conversion jumptable */
|
||||
@@ -980,7 +1004,7 @@ caStatus casStrmClient::createChanResponse(const caHdr &hdr, const pvAttachRetur
|
||||
casChannel *pChan;
|
||||
casChannelI *pChanI;
|
||||
caHdr *claim_reply;
|
||||
unsigned dbrType;
|
||||
unsigned nativeType;
|
||||
bufSizeT nBytes;
|
||||
caStatus status;
|
||||
|
||||
@@ -998,6 +1022,21 @@ caStatus casStrmClient::createChanResponse(const caHdr &hdr, const pvAttachRetur
|
||||
return this->channelCreateFailed (&hdr, S_casApp_pvNotFound);
|
||||
}
|
||||
|
||||
//
|
||||
// fetch the native type
|
||||
//
|
||||
status = pPV->bestDBRType(nativeType);
|
||||
if (status) {
|
||||
errMessage(status, "best external dbr type fetch failed");
|
||||
return this->channelCreateFailed (&hdr, status);
|
||||
}
|
||||
|
||||
//
|
||||
// fetch string conversion table so that we can perform proper conversion
|
||||
// of enumerated PVs to strings during reads
|
||||
//
|
||||
pPV->updateEnumStringTable (nativeType);
|
||||
|
||||
//
|
||||
// attach the PV to this server
|
||||
//
|
||||
@@ -1046,14 +1085,6 @@ caStatus casStrmClient::createChanResponse(const caHdr &hdr, const pvAttachRetur
|
||||
return this->channelCreateFailed(&hdr, status);
|
||||
}
|
||||
|
||||
status = pPV->bestDBRType(dbrType);
|
||||
if (status) {
|
||||
this->outBuf::popCtx (outctx);
|
||||
errMessage(status, "best external dbr type fetch failed");
|
||||
pChanI->destroyNoClientNotify();
|
||||
return this->channelCreateFailed(&hdr, status);
|
||||
}
|
||||
|
||||
//
|
||||
// NOTE:
|
||||
// We are allocated enough space for both the claim
|
||||
@@ -1069,7 +1100,7 @@ caStatus casStrmClient::createChanResponse(const caHdr &hdr, const pvAttachRetur
|
||||
|
||||
*claim_reply = nill_msg;
|
||||
claim_reply->m_cmmd = CA_PROTO_CLAIM_CIU;
|
||||
claim_reply->m_dataType = dbrType;
|
||||
claim_reply->m_dataType = nativeType;
|
||||
claim_reply->m_count = pPV->nativeCount();
|
||||
claim_reply->m_cid = hdr.m_cid;
|
||||
claim_reply->m_available = pChanI->getSID();
|
||||
@@ -1752,14 +1783,13 @@ caStatus casStrmClient::writeArrayData()
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// casStrmClient::read()
|
||||
//
|
||||
caStatus casStrmClient::read(smartGDDPointer &pDescRet)
|
||||
{
|
||||
const caHdr *pHdr = this->ctx.getMsg();
|
||||
caStatus status;
|
||||
const caHdr *pHdr = this->ctx.getMsg();
|
||||
caStatus status;
|
||||
|
||||
pDescRet = NULL;
|
||||
status = createDBRDD (pHdr->m_dataType, pHdr->m_count, pDescRet);
|
||||
@@ -1955,7 +1985,6 @@ caStatus createDBRDD (unsigned dbrType, aitIndex dbrCount, smartGDDPointer &pDes
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// casStrmClient::userName()
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user