// // fileDescriptorManager.process(delay); // (the name of the global symbol has leaked in here) // // // Example EPICS CA server // #include "exServer.h" // // if the compiler supports explicit instantiation of // template member functions // #if defined(EXPL_TEMPL) // // From Stroustrups's "The C++ Programming Language" // Appendix A: r.14.9 // // This explicitly instantiates the template class's // member functions into "templInst.o" // template class gddAppFuncTable ; template class resTable ; #endif // // static list of pre-created PVs // pvInfo exServer::pvList[] = { pvInfo (1.0e-1, "jane", 10.0f, 0.0f, excasIoSync, 1u), pvInfo (2.0, "fred", 10.0f, -10.0f, excasIoSync, 1u), pvInfo (1.0e-1, "janet", 10.0f, 0.0f, excasIoAsync, 1u), pvInfo (2.0, "freddy", 10.0f, -10.0f, excasIoAsync, 1u), pvInfo (2.0, "alan", 10.0f, -10.0f, excasIoSync, 100u), pvInfo (20.0, "albert", 10.0f, -10.0f, excasIoSync, 1000u) }; // // static on-the-fly PVs // pvInfo exServer::bill (2.0, "bill", 10.0f, -10.0f, excasIoSync, 1u); pvInfo exServer::billy (2.0, "billy", 10.0f, -10.0f, excasIoAsync, 1u); // // exServer::exServer() // exServer::exServer(const char * const pvPrefix, unsigned aliasCount, aitBool scanOnIn) : caServer(NELEMENTS(this->pvList)+2u), simultAsychIOCount(0u), scanOn(scanOnIn) { unsigned i; exPV *pPV; pvInfo *pPVI; pvInfo *pPVAfter = &exServer::pvList[NELEMENTS(exServer::pvList)]; int resLibStatus; char pvAlias[256]; const char * const pNameFmtStr = "%.100s%.20s"; const char * const pAliasFmtStr = "%.100s%.20s%u"; exPV::initFT(); // // hash table size may need adjustment here? // resLibStatus = this->stringResTbl.init(NELEMENTS(this->pvList)*(aliasCount+1u)+2u); if (resLibStatus) { fprintf(stderr, "CAS: string resource id table init failed\n"); // // should throw an exception once this is portable // assert(resLibStatus==0); } // // pre-create all of the simple PVs that this server will export // for (pPVI = exServer::pvList; pPVI < pPVAfter; pPVI++) { pPV = pPVI->createPV (*this, aitTrue, scanOnIn); if (!pPV) { fprintf(stderr, "Unable to create new PV \"%s\"\n", pPVI->getName()); } // // Install canonical (root) name // sprintf(pvAlias, pNameFmtStr, pvPrefix, pPVI->getName()); this->installAliasName(*pPVI, pvAlias); // // Install numbered alias names // for (i=0u; igetName(), i); this->installAliasName(*pPVI, pvAlias); } } // // Install create on-the-fly PVs // into the PV name hash table // sprintf(pvAlias, pNameFmtStr, pvPrefix, bill.getName()); this->installAliasName(bill, pvAlias); sprintf(pvAlias, pNameFmtStr, pvPrefix, billy.getName()); this->installAliasName(billy, pvAlias); } // // exServer::~exServer() // exServer::~exServer() { pvInfo *pPVI; pvInfo *pPVAfter = &exServer::pvList[NELEMENTS(exServer::pvList)]; // // delete all pre-created PVs (eliminate bounds-checker warnings) // for (pPVI = exServer::pvList; pPVI < pPVAfter; pPVI++) { pPVI->deletePV (); } } // // exServer::installAliasName() // void exServer::installAliasName(pvInfo &info, const char *pAliasName) { pvEntry *pEntry; pEntry = new pvEntry(info, *this, pAliasName); if (pEntry) { int resLibStatus; resLibStatus = this->stringResTbl.add(*pEntry); if (resLibStatus==0) { return; } else { delete pEntry; } } fprintf(stderr, "Unable to enter PV=\"%s\" Alias=\"%s\" in PV name alias hash table\n", info.getName(), pAliasName); } // // exServer::pvExistTest() // pvExistReturn exServer::pvExistTest (const casCtx& ctxIn, const char *pPVName) { // // lifetime of id is shorter than lifetime of pName // stringId id(pPVName, stringId::refString); pvEntry *pPVE; // // Look in hash table for PV name (or PV alias name) // pPVE = this->stringResTbl.lookup(id); if (!pPVE) { return pverDoesNotExistHere; } pvInfo &pvi = pPVE->getInfo(); // // Initiate async IO if this is an async PV // if (pvi.getIOType() == excasIoSync) { return pverExistsHere; } else { if (this->simultAsychIOCount>=maxSimultAsyncIO) { return pverDoesNotExistHere; } this->simultAsychIOCount++; exAsyncExistIO *pIO; pIO = new exAsyncExistIO(pvi, ctxIn, *this); if (pIO) { return pverAsyncCompletion; } else { return pverDoesNotExistHere; } } } // // exServer::createPV() // pvCreateReturn exServer::createPV (const casCtx &ctx, const char *pName) { // // lifetime of id is shorter than lifetime of pName // stringId id(pName, stringId::refString); exPV *pPV; pvEntry *pPVE; pPVE = this->stringResTbl.lookup(id); if (!pPVE) { return S_casApp_pvNotFound; } pvInfo &pvi = pPVE->getInfo(); // // If this is a synchronous PV create the PV now // if (pvi.getIOType() == excasIoSync) { pPV = pvi.createPV(*this, aitFalse, this->scanOn); if (pPV) { return *pPV; } else { return S_casApp_noMemory; } } // // Initiate async IO if this is an async PV // else { if (this->simultAsychIOCount>=maxSimultAsyncIO) { return S_casApp_postponeAsyncIO; } this->simultAsychIOCount++; exAsyncCreateIO *pIO = new exAsyncCreateIO(pvi, *this, ctx, this->scanOn); if (pIO) { return S_casApp_asyncCompletion; } else { return S_casApp_noMemory; } } } // // pvInfo::createPV() // exPV *pvInfo::createPV (exServer &exCAS, aitBool preCreateFlag, aitBool scanOn) { if (this->pPV) { return this->pPV; } exPV *pNewPV; // // create an instance of the appropriate class // depending on the io type and the number // of elements // if (this->elementCount==1u) { switch (this->ioType){ case excasIoSync: pNewPV = new exScalarPV (*this, preCreateFlag, scanOn); break; case excasIoAsync: pNewPV = new exAsyncPV (*this, preCreateFlag, scanOn); break; default: pNewPV = NULL; break; } } else { if (this->ioType==excasIoSync) { pNewPV = new exVectorPV (*this, preCreateFlag, scanOn); } else { pNewPV = NULL; } } // // load initial value (this is not done in // the constructor because the base class's // pure virtual function would be called) // // We always perform this step even if // scanning is disable so that there will // always be an initial value // if (pNewPV) { this->pPV = pNewPV; pNewPV->scan(); } return pNewPV; } // // exServer::show() // void exServer::show (unsigned level) const { // // server tool specific show code goes here // this->stringResTbl.show(level); // // print information about ca server libarary // internals // this->caServer::show(level); } // // this is a noop that postpones the timer expiration // destroy so the exAsyncIO class will hang around until the // casAsyncIO::destroy() is called // void exOSITimer::destroy() { } // // exAsyncExistIO::expire() // (a virtual function that runs when the base timer expires) // void exAsyncExistIO::expire() { // // post IO completion // this->postIOCompletion (pvExistReturn(pverExistsHere)); } // // exAsyncExistIO::name() // const char *exAsyncExistIO::name() const { return "exAsyncExistIO"; } // // exAsyncCreateIO::expire() // (a virtual function that runs when the base timer expires) // void exAsyncCreateIO::expire() { exPV *pPV; pPV = this->pvi.createPV(this->cas, aitFalse, this->scanOn); if (pPV) { this->postIOCompletion (pvCreateReturn(*pPV)); } else { this->postIOCompletion (pvCreateReturn(S_casApp_noMemory)); } } // // exAsyncCreateIO::name() // const char *exAsyncCreateIO::name() const { return "exAsyncCreateIO"; }