PSEnv/src/EpicsStoreImpl.cpp

Go to the documentation of this file.
00001 //--------------------------------------------------------------------------
00002 // File and Version Information:
00003 //      $Id: EpicsStoreImpl.cpp 8572 2014-07-08 22:23:17Z davidsch@SLAC.STANFORD.EDU $
00004 //
00005 // Description:
00006 //      Class EpicsStoreImpl...
00007 //
00008 // Author List:
00009 //      Andrei Salnikov
00010 //
00011 //------------------------------------------------------------------------
00012 
00013 //-----------------------
00014 // This Class's Header --
00015 //-----------------------
00016 #include "PSEnv/EpicsStoreImpl.h"
00017 
00018 //-----------------
00019 // C/C++ Headers --
00020 //-----------------
00021 #include <sstream>
00022 #include <boost/lexical_cast.hpp>
00023 
00024 //-------------------------------
00025 // Collaborating Class Headers --
00026 //-------------------------------
00027 #include "MsgLogger/MsgLogger.h"
00028 
00029 //-----------------------------------------------------------------------
00030 // Local Macros, Typedefs, Structures, Unions and Forward Declarations --
00031 //-----------------------------------------------------------------------
00032 
00033 namespace {
00034 
00035   const char* logger = "EpicsStore";
00036   
00037   // time diff in seconds between EPICS epoch and UNIX epoch
00038   unsigned sec_1970_to_1990 = (20*365 + 5)*24*3600;
00039 
00040   std::string pvId2str(const std::tr1::tuple<uint32_t, uint32_t, int> &pvId) {
00041     std::stringstream o;
00042     o << "src.log=0x" << std::hex << std::tr1::get<0>(pvId)
00043       << " src.phy=0x" << std::hex << std::tr1::get<1>(pvId)
00044       << " pvId=" << std::dec << std::tr1::get<2>(pvId);
00045     return o.str();
00046   }
00047     
00048 
00049 }
00050 
00051 //              ----------------------------------------
00052 //              -- Public Function Member Definitions --
00053 //              ----------------------------------------
00054 
00055 namespace PSEnv {
00056 
00057 //----------------
00058 // Constructors --
00059 //----------------
00060 EpicsStoreImpl::EpicsStoreImpl ()
00061   : m_id2name()
00062   , m_name2id()
00063   , m_id2alias()
00064   , m_alias2id()
00065   , m_ctrlMap()
00066   , m_timeMap()
00067 {
00068 }
00069 
00070 //--------------
00071 // Destructor --
00072 //--------------
00073 EpicsStoreImpl::~EpicsStoreImpl ()
00074 {
00075 }
00076 
00077 /// Store EPICS PV
00078 void 
00079 EpicsStoreImpl::store(const boost::shared_ptr<Psana::Epics::EpicsPvHeader>& pv, const Pds::Src& src, 
00080                       const std::string *pvName, long eventTag)
00081 {
00082   PvId pvid(src.log(), src.phy(), pv->pvId());
00083 
00084   if (pv->isTime()) {
00085 
00086     // set name from passed in pvName, or find a name, or build fictional one
00087     std::string name;
00088     if (pvName != NULL) { 
00089       name = *pvName;
00090       MsgLog(logger, debug, "EpicsStore::store - storing TIME PV with passed in name=" << *pvName);
00091     } else {
00092       ID2Name::const_iterator it = m_id2name.find(pvid);
00093       if (it != m_id2name.end()) {
00094         name = it->second;
00095       } else {
00096         name = "PV:pvId=" + boost::lexical_cast<std::string>(pv->pvId()) +
00097           ":src_log=" + boost::lexical_cast<std::string>(src.log()) +
00098           ":src_phy=" + boost::lexical_cast<std::string>(src.phy());
00099         m_id2name.insert(std::make_pair(pvid, name));
00100         m_name2id.insert(std::make_pair(name, pvid));
00101         MsgLog(logger, warning, "EpicsStore::store - no name found. Created fictional name: " << name);
00102       }
00103       MsgLog(logger, debug, "EpicsStore::store - storing TIME PV with id=" << pv->pvId());
00104     }
00105     boost::shared_ptr<Psana::Epics::EpicsPvTimeHeader> tpv =
00106         boost::static_pointer_cast<Psana::Epics::EpicsPvTimeHeader>(pv);
00107     bool updatePv = true;
00108     bool eventTagSpecified = eventTag >= 0;
00109     if (eventTagSpecified) {
00110       TimeMap::iterator pos = m_timeMap.find(name);
00111       if (pos != m_timeMap.end()) {
00112         TimeHeaderAndEventTag &storedTimeHeaderAndEventTag = pos->second;
00113         long storedEventTag = storedTimeHeaderAndEventTag.eventTag;
00114         if (storedEventTag == eventTag) {
00115           // check stamps
00116           boost::shared_ptr<Psana::Epics::EpicsPvTimeHeader> storedTimePV = storedTimeHeaderAndEventTag.pv;
00117           const Psana::Epics::epicsTimeStamp storedStamp = storedTimePV->stamp();
00118           const Psana::Epics::epicsTimeStamp currentStamp = tpv->stamp();
00119           bool currentPvIsOlderThanStoredPv = ((currentStamp.sec() < storedStamp.sec()) or
00120                                                ((currentStamp.sec() == storedStamp.sec()) and 
00121                                                 (currentStamp.nsec() < storedStamp.nsec())));
00122           if (currentPvIsOlderThanStoredPv) {
00123             updatePv = false;
00124           }
00125         }
00126       }
00127     }
00128     if (updatePv) {
00129       m_timeMap[name] = TimeHeaderAndEventTag(tpv,eventTag);
00130     }
00131     
00132   } else if (pv->isCtrl()) {
00133 
00134     MsgLog(logger, debug, "EpicsStore::store - storing CTRL PV with id=" << pv->pvId());
00135     boost::shared_ptr<Psana::Epics::EpicsPvCtrlHeader> ctrl =
00136         boost::static_pointer_cast<Psana::Epics::EpicsPvCtrlHeader>(pv);
00137     std::string name = ctrl->pvName();
00138     Name2ID::iterator matchingAliasPos = m_alias2id.find(name);
00139     bool aliasNameFoundThatIsThisPvName = (matchingAliasPos != m_alias2id.end());
00140     if ( aliasNameFoundThatIsThisPvName ) {
00141       MsgLog(logger, trace, "EpicsStore::store - alias: " << name
00142              << " is also used for a pvName. Discarding its use as an alias");
00143       PvId pvId = matchingAliasPos->second;
00144       ID2Name::iterator matchingAliasIdPos = m_id2alias.find(pvId);
00145       m_alias2id.erase(matchingAliasPos);
00146       if (matchingAliasIdPos != m_id2alias.end()) {
00147         m_id2alias.erase(matchingAliasIdPos);
00148       } else {
00149         MsgLog(logger,debug, "EpicsStore::store - while removing alias " << name
00150                << " could not find it's pvId: " << ::pvId2str(pvId)
00151                << " in the id2alias map. Unexpected");
00152       }
00153     }
00154       
00155     m_id2name.insert(std::make_pair(pvid, name));
00156     m_name2id.insert(std::make_pair(name, pvid));
00157     m_ctrlMap[name] = ctrl;
00158     
00159   } else {
00160     
00161     MsgLog(logger, warning, "EpicsStore::store - unexpected PV type: ID=" << pv->pvId() << " type=" << pv->dbrType());
00162     
00163   }
00164 }
00165 
00166 
00167 /// Store alias name for EPICS PV.
00168 void
00169 EpicsStoreImpl::storeAlias(const Pds::Src& src, int pvId, const std::string& alias)
00170 {
00171   bool aliasIsAlsoPvName = m_name2id.find(alias) != m_name2id.end();
00172   if (aliasIsAlsoPvName) {
00173     MsgLog(logger, trace, "EpicsStore::storeAlias - alias: " << alias 
00174            << " is also used for a pvName. Discarding its use as an alias");
00175     return;
00176   }
00177   PvId pvid(src.log(), src.phy(), pvId);
00178   ID2Name::iterator pvIdPos = m_id2alias.find(pvid);
00179   bool pvIdAlreadStored = (pvIdPos != m_id2alias.end());
00180   if (pvIdAlreadStored) {
00181     const std::string &previousAlias = pvIdPos->second;
00182     if (previousAlias != alias) {
00183       MsgLog(logger,trace,"EpicsStore::storeAlias - pvId " << ::pvId2str(pvid)
00184              << " has already been used with alias: " << previousAlias
00185              << ". Attempt to store new alias: " << alias
00186              << ". The new alias will not be stored.");
00187     }
00188     return;
00189   }
00190   m_alias2id[alias] = pvid;
00191   m_id2alias[pvid] = alias;
00192 }
00193 
00194 
00195 /// Get the full list of PV names and aliases
00196 void
00197 EpicsStoreImpl::names(std::vector<std::string>& names) const
00198 {
00199   names.clear();
00200   names.reserve(m_name2id.size() + m_alias2id.size());
00201   for (Name2ID::const_iterator it = m_name2id.begin(); it != m_name2id.end(); ++ it) {
00202     names.push_back(it->first);
00203   }
00204   for (Name2ID::const_iterator it = m_alias2id.begin(); it != m_alias2id.end(); ++ it) {
00205     names.push_back(it->first);
00206   }
00207   // check for pv names that may have come directly through the store routine:
00208   for (TimeMap::const_iterator it = m_timeMap.begin(); it != m_timeMap.end(); ++ it) {
00209     bool nameAlreadyAdded = (m_name2id.find(it->first) != m_name2id.end());
00210     if (not nameAlreadyAdded) {
00211       names.push_back(it->first);
00212     }
00213   }
00214 }
00215 
00216 /// Get the list of PV names
00217 void
00218 EpicsStoreImpl::pvNames(std::vector<std::string>& names) const
00219 {
00220   names.clear();
00221   names.reserve(m_name2id.size());
00222   for (Name2ID::const_iterator it = m_name2id.begin(); it != m_name2id.end(); ++ it) {
00223     names.push_back(it->first);
00224   }
00225   // check for pv names that may have come directly through the store routine:
00226   for (TimeMap::const_iterator it = m_timeMap.begin(); it != m_timeMap.end(); ++ it) {
00227     bool nameAlreadyAdded = (m_name2id.find(it->first) != m_name2id.end());
00228     if (not nameAlreadyAdded) {
00229       names.push_back(it->first);
00230     }
00231   }
00232 }
00233 
00234 /// Get the list of PV aliases.
00235 void 
00236 EpicsStoreImpl::aliases(std::vector<std::string>& names) const
00237 {
00238   names.clear();
00239   names.reserve(m_alias2id.size());
00240   for (Name2ID::const_iterator it = m_alias2id.begin(); it != m_alias2id.end(); ++ it) {
00241     names.push_back(it->first);
00242   }
00243 }
00244 
00245 /// Get alias name for specified PV name.
00246 std::string
00247 EpicsStoreImpl::alias(const std::string& pv) const
00248 {
00249   std::string name;
00250 
00251   Name2ID::const_iterator it = m_name2id.find(pv);
00252   if (it != m_name2id.end()) {
00253     ID2Name::const_iterator ait = m_id2alias.find(it->second);
00254     if (ait != m_id2alias.end()) name = ait->second;
00255   }
00256 
00257   return name;
00258 }
00259 
00260 /// Get PV name for specified alias name.
00261 std::string
00262 EpicsStoreImpl::pvName(const std::string& alias) const
00263 {
00264   std::string name;
00265 
00266   Name2ID::const_iterator ait = m_alias2id.find(alias);
00267   if (ait != m_alias2id.end()) {
00268     ID2Name::const_iterator it = m_id2name.find(ait->second);
00269     if (it != m_id2name.end()) name = it->second;
00270   }
00271 
00272   return name;
00273 }
00274 
00275 
00276 /// Get base class object for given EPICS PV name
00277 boost::shared_ptr<Psana::Epics::EpicsPvHeader>
00278 EpicsStoreImpl::getAny(const std::string& name) const
00279 {
00280   // check for alias
00281   std::string pvName = this->pvName(name);
00282   if (pvName.empty()) pvName = name;
00283 
00284   // try TIME objects first
00285   TimeMap::const_iterator time_it = m_timeMap.find(pvName);
00286   if (time_it != m_timeMap.end()) return (time_it->second).pv;
00287 
00288   // try CTRL objects
00289   CrtlMap::const_iterator ctrl_it = m_ctrlMap.find(pvName);
00290   if (ctrl_it != m_ctrlMap.end()) return ctrl_it->second;
00291 
00292   return boost::shared_ptr<Psana::Epics::EpicsPvHeader>();
00293 }
00294 
00295 
00296 //   Get status info for the EPICS PV.
00297 void
00298 EpicsStoreImpl::getStatus(const std::string& name, int& status, int& severity, PSTime::Time& time) const 
00299 {
00300   // check for alias
00301   std::string pvName = this->pvName(name);
00302   if (pvName.empty()) pvName = name;
00303 
00304   // try TIME objects first
00305   TimeMap::const_iterator time_it = m_timeMap.find(pvName);
00306   if (time_it != m_timeMap.end()) {
00307     Psana::Epics::EpicsPvTimeHeader* tpv = (time_it->second).pv.get();
00308     status = tpv->status();
00309     severity = tpv->severity();
00310     const Psana::Epics::epicsTimeStamp& stamp = tpv->stamp();
00311     time = PSTime::Time(stamp.sec()+sec_1970_to_1990, stamp.nsec());
00312     return;
00313   }
00314 
00315   // try CTRL objects
00316   CrtlMap::const_iterator ctrl_it = m_ctrlMap.find(pvName);
00317   if (ctrl_it != m_ctrlMap.end()) {
00318     Psana::Epics::EpicsPvCtrlHeader* cpv = ctrl_it->second.get();
00319     status = cpv->status();
00320     severity = cpv->severity();
00321     time = PSTime::Time();
00322     return;
00323   }
00324 
00325   // impossible to be here
00326   throw ExceptionEpicsName(ERR_LOC, name);
00327 }
00328 
00329 // Implementation of the getCtrl which returns generic pointer
00330 boost::shared_ptr<Psana::Epics::EpicsPvCtrlHeader>
00331 EpicsStoreImpl::getCtrlImpl(const std::string& name) const
00332 {
00333   // check for alias
00334   std::string pvName = this->pvName(name);
00335   if (pvName.empty()) pvName = name;
00336 
00337   CrtlMap::const_iterator pvit = m_ctrlMap.find(pvName);
00338   if (pvit == m_ctrlMap.end()) return boost::shared_ptr<Psana::Epics::EpicsPvCtrlHeader>();
00339   return pvit->second;
00340 }
00341 
00342 // Implementation of the getTime which returns generic pointer
00343 boost::shared_ptr<Psana::Epics::EpicsPvTimeHeader>
00344 EpicsStoreImpl::getTimeImpl(const std::string& name) const
00345 {
00346   // check for alias
00347   std::string pvName = this->pvName(name);
00348   if (pvName.empty()) pvName = name;
00349 
00350   TimeMap::const_iterator pvit = m_timeMap.find(pvName);
00351   if (pvit == m_timeMap.end()) return boost::shared_ptr<Psana::Epics::EpicsPvTimeHeader>();
00352   return (pvit->second).pv;
00353 }
00354 
00355 // return the timeHeader and eventTag. If the name is not stored, return
00356 // the a default TimeHeaderAndEventTag where the pv is NULL
00357 EpicsStoreImpl::TimeHeaderAndEventTag EpicsStoreImpl::getTimeAndEventTag(const std::string& name) const
00358 {
00359   // check for alias
00360   std::string pvName = this->pvName(name);
00361   if (pvName.empty()) pvName = name;
00362 
00363   TimeMap::const_iterator pvit = m_timeMap.find(pvName);
00364   if (pvit == m_timeMap.end()) return TimeHeaderAndEventTag();
00365   return pvit->second;
00366 }
00367 
00368 } // namespace PSEnv

Generated on 19 Dec 2016 for PSANAclasses by  doxygen 1.4.7