|
solarpowerlog trunk
|
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