solarpowerlog trunk
/home/tobi/workspace/solarpowerlog/src/DataFilters/CDumpOutputFilter.cpp
Go to the documentation of this file.
00001 /* ----------------------------------------------------------------------------
00002  solarpowerlog
00003  Copyright (C) 2009  Tobias Frost
00004 
00005  This file is part of solarpowerlog.
00006 
00007  Solarpowerlog is free software; However, it is dual-licenced
00008  as described in the file "COPYING".
00009 
00010  For this file (CDumpOutputFilter.cpp), the license terms are:
00011 
00012  You can redistribute it and/or modify it under the terms of the GNU
00013  General Public License as published by the Free Software Foundation; either
00014  version 3 of the License, or (at your option) any later version.
00015 
00016  This program is distributed in the hope that it will be useful, but
00017  WITHOUT ANY WARRANTY; without even the implied warranty of
00018  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  Lesser General Public License for more details.
00020 
00021  You should have received a copy of the GNU Library General Public
00022  License along with this proramm; if not, see
00023  <http://www.gnu.org/licenses/>.
00024  ----------------------------------------------------------------------------
00025  */
00026 
00033 #ifdef HAVE_CONFIG_H
00034 #include "config.h"
00035 #endif
00036 
00037 #ifdef HAVE_FILTER_DUMBDUMP
00038 
00039 #include <assert.h>
00040 
00041 #include "CDumpOutputFilter.h"
00042 #include "DataFilters/interfaces/IDataFilter.h"
00043 #include "configuration/Registry.h"
00044 #include "configuration/CConfigHelper.h"
00045 
00046 #include "Inverters/Capabilites.h"
00047 #include "patterns/ICommand.h"
00048 #include "configuration/Registry.h"
00049 #include "interfaces/CWorkScheduler.h"
00050 #include "Inverters/interfaces/ICapaIterator.h"
00051 #include "patterns/CValue.h"
00052 
00053 #include <cstdio>
00054 
00055 using namespace libconfig;
00056 
00057 CDumpOutputFilter::CDumpOutputFilter( const string &name,
00058      const string & configurationpath ) :
00059      IDataFilter(name, configurationpath), AddedCaps(0)
00060 {
00061      // Schedule the initialization and subscriptions later...
00062      ICommand *cmd = new ICommand(CMD_INIT, this);
00063      Registry::GetMainScheduler()->ScheduleWork(cmd);
00064 
00065      CCapability *c = IInverterBase::GetConcreteCapability(
00066           CAPA_INVERTER_DATASTATE);
00067      CapabilityMap.erase(CAPA_INVERTER_DATASTATE);
00068      delete c;
00069 
00070 }
00071 
00072 CDumpOutputFilter::~CDumpOutputFilter()
00073 {
00074      if (base) {
00075           auto_ptr<ICapaIterator> it(base->GetCapaNewIterator());
00076           pair<string, CCapability*> pair;
00077           while (it->HasNext()) {
00078                pair = it->GetNext();
00079                pair.second->UnSubscribe(this);
00080           }
00081      }
00082 }
00083 
00084 bool CDumpOutputFilter::CheckConfig()
00085 {
00086      string setting;
00087      string str;
00088      bool fail = false;
00089 
00090      CConfigHelper hlp(configurationpath);
00091      fail |= !hlp.CheckConfig("datasource", Setting::TypeString);
00092      fail |= !hlp.CheckConfig("clearscreen", Setting::TypeBoolean, true);
00093 
00094      hlp.GetConfig("datasource", str, (std::string) "");
00095      IInverterBase *i = Registry::Instance().GetInverter(str);
00096      if (!i) {
00097           LOGERROR(logger, "Setting " << setting << " in " << configurationpath
00098                << "." << name
00099                << ": Cannot find instance of Inverter with the name "
00100                << str );
00101           fail = true;
00102      }
00103      return !fail;
00104 }
00105 
00106 void CDumpOutputFilter::Update( const IObserverSubject *subject )
00107 {
00108      assert (subject);
00109 
00110      // note: the subject must be a CCapability here.
00111      // to avoid neverending casting we do that once.
00112      CCapability *parentcap = (CCapability *) subject;
00113      CCapability *ourcap;
00114 
00115      // check for the mandatory Capas now, as they might require
00116      // immediate actions.
00117      if (parentcap->getDescription() == CAPA_CAPAS_REMOVEALL) {
00118           // forward the notification.
00119           // but -- to be nice -- update the value first
00120           ourcap = IInverterBase::GetConcreteCapability(CAPA_CAPAS_REMOVEALL);
00121           assert (ourcap);
00122           assert (ourcap->getValue()->GetType() == CAPA_CAPAS_REMOVEALL_TYPE);
00123           assert (parentcap->getValue()->GetType() == CAPA_CAPAS_REMOVEALL_TYPE);
00124 
00125           CValue<bool> *a, *b;
00126           a = (CValue<bool> *) (ourcap->getValue());
00127           b = (CValue<bool> *) (parentcap->getValue());
00128           *a = *b;
00129           ourcap->Notify();
00130 
00131           CheckOrUnSubscribe(false);
00132           return;
00133      }
00134 
00135      if (parentcap->getDescription() == CAPA_CAPAS_UPDATED) {
00136           // this one will be dereferred, but only if we do
00137           // not have one pending.
00138           if (AddedCaps)
00139                return;
00140           AddedCaps = true;
00141           ICommand *cmd = new ICommand(CMD_ADDED_CAPAS, this);
00142           Registry::GetMainScheduler()->ScheduleWork(cmd);
00143           return;
00144      }
00145 
00146      // All others does not need to handled here, its ok in the cyclic.
00147 
00148 }
00149 
00150 void CDumpOutputFilter::ExecuteCommand( const ICommand *cmd )
00151 {
00152 
00153      switch (cmd->getCmd()) {
00154      case CMD_INIT:
00155      {
00156           string tmp;
00157           CConfigHelper cfghlp(configurationpath);
00158 
00159           cfghlp.GetConfig("clearscreen", this->clearscreen);
00160 
00161           if (cfghlp.GetConfig("datasource", tmp)) {
00162                base = Registry::Instance().GetInverter(tmp);
00163                if (base) {
00164                     CCapability *cap = base->GetConcreteCapability(
00165                          CAPA_CAPAS_UPDATED);
00166                     assert(cap); // this is required to have....
00167                     cap->Subscribe(this);
00168 
00169                     cap = base->GetConcreteCapability(
00170                          CAPA_CAPAS_REMOVEALL);
00171                     assert(cap);
00172                     cap->Subscribe(this);
00173 
00174                     cap = base->GetConcreteCapability(
00175                          CAPA_INVERTER_DATASTATE);
00176                     assert(cap);
00177                     cap->Subscribe(this);
00178                } else {
00179                     LOGWARN(logger,
00180                          "Warning: Could not find data source to connect. Filter: "
00181                          << configurationpath << "." << name);
00182                }
00183           }
00184 
00185           CheckOrUnSubscribe(true);
00186           // falling through
00187      }
00188      case CMD_CYCLIC:
00189      {
00190           ICommand *cmd = new ICommand(CMD_CYCLIC, this);
00191           timespec ts = { 5, 0 };
00192 
00193           CCapability *c = GetConcreteCapability(
00194                CAPA_INVERTER_QUERYINTERVAL);
00195           if (c && c->getValue()->GetType() == IValue::float_type) {
00196                CValue<float> *v = (CValue<float> *) c->getValue();
00197                ts.tv_sec = v->Get();
00198                ts.tv_nsec = ((v->Get() - ts.tv_sec) * 1e9);
00199           }
00200 
00201           Registry::GetMainScheduler()->ScheduleWork(cmd, ts);
00202           DoCyclicWork();
00203           break;
00204      }
00205 
00206      case CMD_UNSUBSCRIBE:
00207           CheckOrUnSubscribe(false);
00208           break;
00209 
00210      case CMD_ADDED_CAPAS:
00211           cout << name << ":" << configurationpath
00212                << " New Capability(ies) reported" << endl;
00213           AddedCaps = false;
00214           CheckOrUnSubscribe(true);
00215           GetConcreteCapability(CAPA_CAPAS_UPDATED)->Notify();
00216           break;
00217 
00218      }
00219 }
00220 
00221 // On serveral updates, we have to go through all subscriptions
00222 // and check, if we have to subscribe to any of them
00223 // The parameter sets, if we subscribe or unsubscribe.
00224 void CDumpOutputFilter::CheckOrUnSubscribe( bool subscribe )
00225 {
00226      if (!base)
00227           return;
00228 
00229      // mmh, i think they are unused... this filter iterates and needs not to
00230      // subscribe.
00231      CCapability *cap = base->GetConcreteCapability(
00232                CAPA_INVERTER_DATASTATE);
00233      if (cap)
00234           cap->SetSubscription(this, subscribe);
00235 
00236 #if 0
00237      CCapability *cap = base->GetConcreteCapability(
00238           CAPA_INVERTER_MANUFACTOR_NAME);
00239      if (cap)
00240           cap->SetSubscription(this, subscribe);
00241 
00242      cap = base->GetConcreteCapability(CAPA_INVERTER_MODEL);
00243      if (cap)
00244           cap->SetSubscription(this, subscribe);
00245 
00246      cap = base->GetConcreteCapability(CAPA_INVERTER_ACPOWER_TOTAL);
00247      if (cap)
00248           cap->SetSubscription(this, subscribe);
00249 
00250      cap = base->GetConcreteCapability(CAPA_INVERTER_KWH_Y2D);
00251      if (cap)
00252           cap->SetSubscription(this, subscribe);
00253 
00254      cap = base->GetConcreteCapability(CAPA_INVERTER_KWH_M2D);
00255      if (cap)
00256           cap->SetSubscription(this, subscribe);
00257 #endif
00258 }
00259 
00263 void CDumpOutputFilter::DoCyclicWork( void )
00264 {
00265 
00266 #if 0
00267      // shows how to browser through our caps.
00268      cout << configurationpath << "." << name << " Own Capabilities:"
00269      << endl << endl;
00270      map<string, CCapability*>::iterator it = GetCapabilityIterator();
00271      while (it != GetCapabilityLastIterator()) {
00272           cout << (*it).first << ' ' << flush;
00273           for (int i = (*it).first.length() + 1; i < 60; i++)
00274           cout << '.';
00275           cout << DumpValue((*it).second->getValue()) << endl;
00276           it++;
00277      }
00278 #endif
00279 
00280      if (clearscreen) {
00281           cout << "\033[2J" << "\033[1;1H";
00282      }
00283 
00284      cout << endl << configurationpath << "." << name
00285           << " Known Capabilities:" << endl << endl;
00286      auto_ptr<ICapaIterator> cit(GetCapaNewIterator());
00287      while (cit->HasNext()) {
00288           pair<string, CCapability*> cappair = cit->GetNext();
00289           cout << (cappair).first << ' ' << flush;
00290           for (int i = (cappair).first.length() + 1; i < 60; i++)
00291                cout << '.';
00292           cout << " " << DumpValue(cappair.second->getValue())
00293                << " (Capa of: "
00294                << cappair.second->getSource()->GetName() << ")"
00295                << endl;
00296      }
00297      cout << endl;
00298 }
00299 
00300 string CDumpOutputFilter::DumpValue( IValue *value )
00301 {
00302      enum IValue::factory_types type = value->GetType();
00303      string ret;
00304      char buf[128];
00305 
00306      switch (type) {
00307      case IValue::bool_type:
00308           ret = ((CValue<bool> *) value)->Get() ? "true/on/active"
00309                : "false/off/inactive";
00310           break;
00311 
00312      case IValue::float_type:
00313           sprintf(buf, "%.2f", ((CValue<float>*) value)->Get());
00314           ret = buf;
00315           break;
00316 
00317      case IValue::int_type:
00318           sprintf(buf, "%d", ((CValue<int>*) value)->Get());
00319           ret = buf;
00320           break;
00321 
00322      case IValue::string_type:
00323           ret = ((CValue<string>*) value) -> Get();
00324           break;
00325      }
00326      return ret;
00327 }
00328 
00329 #endif