ALMA Computing Group

acsexmplFridgeImpl.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 *    ALMA - Atacama Large Millimiter Array
00003 *    (c) European Southern Observatory, 2002
00004 *    Copyright by ESO (in the framework of the ALMA collaboration)
00005 *    and Cosylab 2002, All rights reserved
00006 *
00007 *    This library is free software; you can redistribute it and/or
00008 *    modify it under the terms of the GNU Lesser General Public
00009 *    License as published by the Free Software Foundation; either
00010 *    version 2.1 of the License, or (at your option) any later version.
00011 *
00012 *    This library is distributed in the hope that it will be useful,
00013 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 *    Lesser General Public License for more details.
00016 *
00017 *    You should have received a copy of the GNU Lesser General Public
00018 *    License along with this library; if not, write to the Free Software
00019 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00020 *
00021 *
00022 * "@(#) $Id: acsexmplFridgeImpl.cpp,v 1.134 2009/09/24 23:08:03 javarias Exp $"
00023 *
00024 * who       when      what
00025 * --------  --------  ----------------------------------------------
00026 * acaproni 2004-04-06 Use of smart pointer for properties
00027 * bjeram 2003-04-10 added FRIDGE::OnOffStates state = ... DevIO::write(state, ...) since write takes reference
00028 * david 2002-08-08 changes defines to const static int's
00029 * bgustafs 2002-04-11 Modified for VxWorks
00030 * gchiozzi 2002-04-04 Replaced set_sync() with getDevIO()->write<T>()
00031 * gchiozzi 2002-03-18 Replaced includes of fridge*.* with acsexmplFridge*.*
00032 * msekoran 2001-07-06 improved error handling
00033 * msekoran 2001-03-10 integrated with new BACI; ALMA coding convention used
00034 * gchiozzi 2001-02-15 Added real implementation for method descriptor()
00035 * gchiozzi 2001-02-15 Added body of get_interface() method for Object Explorer
00036 * gchiozzi 2001-02-15 created standard header 
00037 */
00038 
00039 
00040 #include <acsexmplFridgeImpl.h>
00041 #include <math.h>
00042 
00043 ACE_RCSID(acsexmpl, acsexmplFridgeImpl, "$Id: acsexmplFridgeImpl.cpp,v 1.134 2009/09/24 23:08:03 javarias Exp $")
00044 using namespace baci;
00045 
00049 const static int ON_ACTION    = 0;
00050 const static int OFF_ACTION   = 1;
00051 const static int OPEN_ACTION  = 2;
00052 const static int CLOSE_ACTION = 3;
00053 
00059 int LOCALCOUNT = 0;
00060 
00064 ACE_Log_Priority LOCAL_LOGGING_LEVEL = LM_INFO;
00065 
00066 
00067 /*      *
00068  * After the thread's run loop has exceeded MAX_LOGS, the logging
00069  * level goes down to LM_DEBUG.
00070  */
00071 const static int MAX_LOGS = 5;
00072 
00073 
00075 // FridgeThread
00077 
00078 void
00079 FridgeThread::runLoop()
00080 {
00081         //Used to change the logging level to make acsexmpl's modular
00082         //tests more deterministic.
00083         if(LOCALCOUNT>MAX_LOGS)
00084         {
00085                 LOCAL_LOGGING_LEVEL = LM_DEBUG;
00086         }
00087         else
00088         {
00089                 LOCALCOUNT++;
00090         }
00091         ACS_SHORT_LOG((LOCAL_LOGGING_LEVEL, "Updating fridge temperature"));
00092         fridgeControl_p->updateTemperature();
00093 }
00094 
00096 // Fridge
00098 
00099 
00100 /* ----------------------------------------------------------------*/
00101 /* ----------------------------------------------------------------*/
00102 /* ----------------------------------------------------------------*/
00103 FridgeControl::FridgeControl(
00104                              const ACE_CString &name,
00105                              maci::ContainerServices * containerServices) :
00106     CharacteristicComponentImpl(name, containerServices),
00107     m_refTemperature_sp(new RWdouble(name+":refTemperature", getComponent()),this),
00108     m_powerStatus_sp(new ROEnumImpl<ACS_ENUM_T(FRIDGE::OnOffStates), 
00109                      POA_FRIDGE::ROOnOffStates> (name+":powerStatus", getComponent()),this),
00110     m_doorStatus_sp(new ROEnumImpl<ACS_ENUM_T(FRIDGE::OpClStates), 
00111                     POA_FRIDGE::ROOpClStates> (name+":doorStatus", getComponent()),this),
00112     m_currTemperature_sp(new ROdouble(name+":currTemperature", getComponent()),this),
00113     m_controlLoop_p(0),
00114     m_FridgeSupplier_p(0)
00115 {
00116     ACS_TRACE("::FridgeControl::FridgeControl");
00117 
00118     // Handle notification channel creation here.
00119     m_FridgeSupplier_p = new nc::SimpleSupplier(FRIDGE::CHANNELNAME_FRIDGE, this);
00120 }
00121 
00122 FridgeControl::~FridgeControl()
00123 {
00124     
00125     ACS_TRACE("::FridgeControl::~FridgeControl");
00126     ACS_DEBUG_PARAM("::FridgeControl::~FridgeControl", "Destroying %s...", getComponent()->getName());
00127     
00128     // destroy the thread via ThreadManager
00129     if(m_controlLoop_p!=0)
00130         getContainerServices()->getThreadManager()->destroy(m_controlLoop_p);
00131 
00132     // cleanUp will have been already called by
00133     // the container and threads will have been already stopped.
00134 }
00135 
00136 void FridgeControl::cleanUp()
00137 {
00138     ACS_TRACE("::FridgeControl::cleanUp");
00139     
00140     //turn it off before destroying it
00141     ACSErr::Completion_var completion;
00142     if((m_controlLoop_p!=0) && (powerStatus()->get_sync(completion.out())!=FRIDGE::OFF))
00143         {
00144         off();
00145         }
00146     
00147     // Here we have to stop all threads
00148     getContainerServices()->getThreadManager()->stopAll(); 
00149 
00150 
00151     // In the past this was done in the CharacteristicComponentImpl::cleanUp();    
00152     // As required by the CharacteristicComponentImpl class,
00153     // I call explicitly the cleanUp() of the parent class.
00154     // This makes sure that all threads are stopped and the 
00155     // Component's state set.
00156     // Depending on what resources are used by a class implementing a 
00157     // Component and by the implementation of the parent class (if it does 
00158     // not inherit directly from acscomponent::ACSComponentImpl 
00159     // or baci:: CharacteristicComponentImpl) it might be
00160     // necessary to call the cleanuUp() method of the base class 
00161     // AFTER having released resources allocated by  the current class.
00162     // This is demonstrated in this example where we want to make sure
00163     // that the powerStatus is FRIDGE::OFF before letting the
00164     // cleanUp() of the base class stopping all the 
00165     // threads, including the one that regulates the temperature.
00166     // For an example where the cleanUp() of the parent class
00167     // is called before any other step, see the  Building class.
00168     // Always check the documentation of the parent class
00169     // and consider what resources are allocated by this class
00170     // to extablish the requirements for the execution of lifecycle
00171     // chained methods.
00172 
00173     // clean-up associated with NC
00174     if (m_FridgeSupplier_p != 0)
00175         {
00176         m_FridgeSupplier_p->disconnect();
00177         m_FridgeSupplier_p=0;
00178         }
00179 }
00180 void 
00181 FridgeControl::updateTemperature()
00182 {
00183     double temperature;
00184     ACS::Time timestamp;
00185     
00186     
00187     ACS_TRACE("::FridgeControl::updateTemperature");
00188     
00189     ACSErr::Completion_var completion;
00190     double currRefTemperature;
00191     
00192     currRefTemperature = m_refTemperature_sp->get_sync(completion.out());
00193     temperature = m_currTemperature_sp->get_sync(completion.out());
00194 
00195     // simulate the fridge trying to reach the reference temperature.
00196     ACS_SHORT_LOG((LOCAL_LOGGING_LEVEL, "::FridgeControl::updateTemperature. Curr value: %f. Ref: %f", temperature, currRefTemperature));
00197     if(temperature < currRefTemperature)
00198         {
00199         temperature += 0.1;
00200         }
00201     else if(temperature > currRefTemperature)
00202         {
00203         temperature -= 0.1;
00204         }
00205  
00206     m_currTemperature_sp->getDevIO()->write(temperature, timestamp);
00207 
00208     // push data onto the NC
00209     this->loadData();
00210     
00211     ACS_SHORT_LOG((LOCAL_LOGGING_LEVEL, "::FridgeControl::updateTemperature. New value: %f", temperature));
00212     
00213 }
00214 
00215 /* --------------------- [ FRIDGE interface ] ---------------------*/
00216 void
00217 FridgeControl::on ()
00218 {
00219         ACS::Time timestamp;
00220 
00221         ACS_DEBUG_PARAM("::FridgeControl::on", "%s", getComponent()->getName());
00222         m_powerStatus_sp->getDevIO()->write(FRIDGE::ON, timestamp);
00223 
00224         // if the fridge has never been turned on before, we start the thread.  otherwise the 
00225         // fridge goes from off to on.
00226         if(m_controlLoop_p == 0)
00227         {
00228                 FridgeControl * selfPtr = this;
00229                 m_controlLoop_p = getContainerServices()->getThreadManager()->
00230                         create<FridgeThread, FridgeControl*>("fridgeControlLoop", selfPtr);
00231                 m_controlLoop_p->resume();
00232         }
00233         else
00234         {
00235                 m_controlLoop_p->resume();
00236         }
00237 }
00238 
00239 void
00240 FridgeControl::off ()
00241 {
00242     ACS::Time timestamp;
00243 
00244     ACS_DEBUG_PARAM("::FridgeControl::off", "%s", getComponent()->getName());
00245     // if the fridge has been turned on before, it is turned off.  otherwise there
00246     // is no need to do anything.
00247     m_powerStatus_sp->getDevIO()->write(FRIDGE::OFF, timestamp);
00248     if(m_controlLoop_p != 0)
00249         {
00250         m_controlLoop_p->suspend();
00251         }
00252 }
00253 
00254 void
00255 FridgeControl::open ()
00256 {
00257     ACS::Time timestamp;
00258     
00259     ACS_DEBUG_PARAM("::FridgeControl::open", "%s", getComponent()->getName());
00260     // there is no actual door to open here: only the enum is changed
00261     m_doorStatus_sp->getDevIO()->write(FRIDGE::OPEN, timestamp);
00262 }
00263 
00264 void
00265 FridgeControl::close ()
00266 {
00267     ACS::Time timestamp;
00268     
00269     ACS_DEBUG_PARAM("::FridgeControl::close", "%s", getComponent()->getName());
00270     // there is no actual door to close here: only the enum is changed
00271     m_doorStatus_sp->getDevIO()->write( FRIDGE::CLOSE, timestamp);
00272 }
00273 
00274 ACS::RWdouble_ptr
00275 FridgeControl::refTemperature ()
00276 {
00277     if (m_refTemperature_sp == 0)
00278         {
00279         return ACS::RWdouble::_nil();
00280         }
00281     
00282     ACS::RWdouble_var prop = ACS::RWdouble::_narrow(m_refTemperature_sp->getCORBAReference());
00283     return prop._retn();
00284 }
00285 
00286 FRIDGE::ROOnOffStates_ptr
00287 FridgeControl::powerStatus ()
00288 {
00289     if (m_powerStatus_sp == 0)
00290         {
00291         return FRIDGE::ROOnOffStates::_nil();
00292         }
00293     
00294     FRIDGE::ROOnOffStates_var prop = FRIDGE::ROOnOffStates::_narrow(m_powerStatus_sp->getCORBAReference());
00295     return prop._retn();
00296 }
00297 
00298 FRIDGE::ROOpClStates_ptr
00299 FridgeControl::doorStatus ()
00300 {
00301     if (m_doorStatus_sp == 0)
00302         {
00303         return FRIDGE::ROOpClStates::_nil();
00304         }    
00305     
00306     FRIDGE::ROOpClStates_var prop = FRIDGE::ROOpClStates::_narrow(m_doorStatus_sp->getCORBAReference());
00307     return prop._retn();
00308 }
00309  
00310 ACS::ROdouble_ptr
00311 FridgeControl::currTemperature ()
00312 {
00313     if (m_currTemperature_sp == 0)
00314         {
00315         return ACS::ROdouble::_nil();
00316         }
00317     
00318     ACS::ROdouble_var prop = ACS::ROdouble::_narrow(m_currTemperature_sp->getCORBAReference());
00319     return prop._retn();
00320 }
00321 /* --------------------- [ Notification Channel ] -----------------*/
00322 
00323 /* optional */
00324 /* Implement event processing callback */
00325 class FridgeEventsCallback :public nc::SimpleSupplier::EventProcessingCallback
00326                                                                          <FRIDGE::temperatureDataBlockEvent>
00327 {
00328         public:
00329                 void eventDropped(FRIDGE::temperatureDataBlockEvent event)
00330                 {
00331                         ACS_SHORT_LOG((LM_WARNING, "Event Dropped"))
00332                 }
00333                 void eventSent(FRIDGE::temperatureDataBlockEvent event)
00334                 {
00335                         ACS_SHORT_LOG((LOCAL_LOGGING_LEVEL, "Event sent succesfully"))
00336                 }
00337                 void eventStoredInQueue(FRIDGE::temperatureDataBlockEvent event)
00338                 {
00339                         ACS_SHORT_LOG((LOCAL_LOGGING_LEVEL, "Notification Channel is down"))
00340                 }
00341 };
00342 
00343 void 
00344 FridgeControl::loadData()
00345 {
00346     ACS_TRACE("::FridgeControl::loadData()");
00347          
00348          FridgeEventsCallback callback;
00349 
00350     ACSErr::Completion_var completion;
00351     double current=0.0;
00352     double reference=0.0;
00353     current   = currTemperature()->get_sync(completion.out() );
00354     reference = refTemperature()->get_sync(completion.out()  );
00355 
00356     // put the temperature info into a structure that will be pushed onto the NC
00357     FRIDGE::temperatureDataBlockEvent data;
00358     data.absoluteDiff = fabs(current - reference);
00359     if(current > reference)
00360         {
00361         data.status = FRIDGE::OVERREF;
00362         }
00363     else if(current < reference)
00364         {
00365         data.status = FRIDGE::BELOWREF;
00366         }
00367     else
00368         {
00369         data.status = FRIDGE::ATREF;
00370         }
00371 
00372     // push the data - this eventually calls setData
00373     if(m_FridgeSupplier_p)
00374         {
00375         //m_FridgeSupplier_p->publishData<FRIDGE::temperatureDataBlockEvent>(data);
00376                 m_FridgeSupplier_p->publishData<FRIDGE::temperatureDataBlockEvent>
00377                         (data, &callback);
00378         }
00379 }
00380 
00381 
00382 /* --------------- [ MACI DLL support functions ] -----------------*/
00383 #include <maciACSComponentDefines.h>
00384 MACI_DLL_SUPPORT_FUNCTIONS(FridgeControl)
00385 /* ----------------------------------------------------------------*/
00386 
00387 
00388