00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "FWMath.h"
00022 #include "SimpleBattery.h"
00023 #include "BatteryStats.h"
00024
00025 Define_Module(SimpleBattery)
00026 ;
00027
00028 void SimpleBattery::initialize(int stage) {
00029 BaseBattery::initialize(stage);
00030
00031 if (stage == 0) {
00032
00033 voltage = par("voltage");
00034 nominalCapmAh = par("nominal");
00035 if (nominalCapmAh <= 0) {
00036 error("invalid nominal capacity value");
00037 }
00038 capmAh = par("capacity");
00039
00040
00041
00042 publishTime = 0;
00043 publishTime = par("publishTime");
00044 if (publishTime > 0) {
00045 publish = new cMessage("publish", PUBLISH);
00046 publish->setSchedulingPriority(2000);
00047 scheduleAt(simTime() + publishTime, publish);
00048 }
00049 publishDelta = 1;
00050 publishDelta = par("publishDelta");
00051 if (publishDelta < 0 || publishDelta > 1) {
00052 error("invalid publishDelta value");
00053 }
00054
00055 resolution = par("resolution");
00056
00057 debugEV<< "capacity = " << capmAh << "mA-h (nominal = " << nominalCapmAh <<
00058 ") at " << voltage << "V" << endl;
00059 debugEV << "publishDelta = " << publishDelta * 100 << "%, publishTime = "
00060 << publishTime << "s, resolution = " << resolution << "sec"
00061 << endl;
00062
00063 capacity = capmAh * 60 * 60 * voltage;
00064 nominalCapacity = nominalCapmAh * 60 * 60 * voltage;
00065 batteryState = new BatteryState(nominalCapacity);
00066
00067 residualCapacity = lastPublishCapacity = capacity;
00068
00069 lifetime = -1;
00070
00071
00072 residualVec.disable();
00073
00074 residualVec.setName("residualCapacity");
00075 residualVec.record(residualCapacity);
00076
00077 timeout = new cMessage("auto-update", AUTO_UPDATE);
00078 timeout->setSchedulingPriority(500);
00079 scheduleAt(simTime() + resolution, timeout);
00080
00081
00082 scopeHost = (this->findHost())->getId();
00083 hostStateCat = utility->getCategory(&hostState);
00084
00085
00086 if (publishDelta < 1 || publishTime> 0)
00087 batteryCat = utility->getCategory(batteryState);
00088
00089 numDevices = hasPar("numDevices") ? par("numDevices") : 0;
00090 if (numDevices == 0) {
00091 EV << "Warning: no devices attached to battery\n";
00092 }
00093 registeredDevices = 0;
00094
00095 devices = new DeviceEntry[numDevices];
00096 lastUpdateTime = simTime();
00097 }
00098
00099 if (stage == 1) {
00100 hostState.set(HostState::ACTIVE);
00101 utility->publishBBItem(hostStateCat, &hostState, scopeHost);
00102
00103 if (publishDelta < 1 || publishTime> 0 ) {
00104 batteryState->set(residualCapacity);
00105 utility->publishBBItem(batteryCat, batteryState, scopeHost);
00106 }
00107 }
00108 }
00109
00110 int SimpleBattery::registerDevice(const std::string& name, int numAccts)
00111 {
00112 int deviceID = registeredDevices++;
00113
00114 if(registeredDevices > numDevices) {
00115 error("To much devices registered with battery. Please adjust the Batteries numDevices parameter!");
00116 }
00117
00118 if (!devices[deviceID].name.empty()) {
00119 error("device already registered!");
00120 }
00121
00122 devices[deviceID].name = name;
00123
00124 if (numAccts < 1) {
00125 error("number of activities must be at least 1");
00126 }
00127 devices[deviceID].numAccts = numAccts;
00128
00129 double *accts = new double[numAccts];
00130 for (int i = 0; i < numAccts; i++) {
00131 accts[i] = 0.0;
00132 }
00133 devices[deviceID].accts = accts;
00134
00135 simtime_t *times = new simtime_t[numAccts];
00136 for (int i = 0; i < numAccts; i++) {
00137 times[i] = 0.0;
00138 }
00139 devices[deviceID].times = times;
00140
00141 debugEV<< "initialized device " << devices[deviceID].name << " as device "
00142 << deviceID << " with " << devices[deviceID].numAccts <<
00143 " accounts" << endl;
00144
00145 return deviceID;
00146 }
00147
00148 void SimpleBattery::draw(int deviceID, DrawAmount& amount, int activity)
00149 {
00150 if(deviceID < 0 || deviceID > registeredDevices) {
00151 error("Unknown device ID!");
00152 }
00153
00154 if (amount.getType() == DrawAmount::CURRENT) {
00155
00156 if (devices[deviceID].name.empty()) {
00157 error("drawMsg from unregistered device");
00158 }
00159
00160 double current = amount.getValue();
00161 if (activity < 0 && current != 0)
00162 error("invalid CURRENT message");
00163
00164 debugEV << simTime() << " device " << deviceID <<
00165 " (" << devices[deviceID].name << ") draw current " << current <<
00166 "mA, activity = " << activity << endl;
00167
00168
00169 deductAndCheck();
00170
00171
00172 devices[deviceID].draw = current;
00173 devices[deviceID].currentActivity = activity;
00174 }
00175
00176 else if (amount.getType() == DrawAmount::ENERGY) {
00177
00178 if (devices[deviceID].name.empty()) {
00179 error("drawMsg from unregistered device");
00180 }
00181 double energy = amount.getValue();
00182 if (!(activity >=0 && activity < devices[deviceID].numAccts)) {
00183 error("invalid activity specified");
00184 }
00185
00186 debugEV << simTime() << " device " << deviceID <<
00187 " (" << devices[deviceID].name << ") deduct " << energy <<
00188 " mW-s, activity = " << activity << endl;
00189
00190
00191 devices[deviceID].accts[activity] += energy;
00192 residualCapacity -= energy;
00193
00194
00195
00196 deductAndCheck();
00197 }
00198 else {
00199 error("Unknown power type!");
00200 }
00201 }
00202
00203 void SimpleBattery::handleMessage(cMessage *msg) {
00204 if (msg->isSelfMessage()) {
00205
00206 switch (msg->getKind()) {
00207 case AUTO_UPDATE:
00208
00209 scheduleAt(simTime() + resolution, timeout);
00210 deductAndCheck();
00211 break;
00212
00213 case PUBLISH:
00214
00215 utility->publishBBItem(batteryCat, batteryState, scopeHost);
00216 lastPublishCapacity = residualCapacity;
00217
00218 scheduleAt(simTime() + publishTime, publish);
00219 break;
00220
00221 default:
00222 error("battery receives mysterious timeout");
00223 break;
00224 }
00225 } else {
00226 error("unexpected message");
00227 delete msg;
00228 }
00229 }
00230
00231 void SimpleBattery::handleHostState(const HostState& state)
00232 {
00233
00234 }
00235
00236 void SimpleBattery::deductAndCheck() {
00237
00238
00239 if (residualCapacity <= 0) {
00240 return;
00241 }
00242
00243 simtime_t now = simTime();
00244
00245
00246
00247
00248
00249
00250
00251 for (int i = 0; i < numDevices; i++) {
00252 int currentActivity = devices[i].currentActivity;
00253 if (currentActivity > -1) {
00254 double energy = devices[i].draw * voltage * (now - lastUpdateTime).dbl();
00255 if (energy > 0) {
00256 devices[i].accts[currentActivity] += energy;
00257 devices[i].times[currentActivity] += (now - lastUpdateTime);
00258 residualCapacity -= energy;
00259 }
00260 }
00261 }
00262
00263 lastUpdateTime = now;
00264
00265 debugEV<< simTime() << ": residual capacity = "
00266 << residualCapacity << endl;
00267
00268
00269 if (residualCapacity <= 0.0 ) {
00270
00271 EV << "battery depleted at t = " << now << "s" << endl;
00272
00273 lifetime = now;
00274
00275
00276 hostState.set(HostState::FAILED);
00277 utility->publishBBItem(hostStateCat, &hostState, scopeHost);
00278
00279
00280 if (publishDelta < 1 || publishTime> 0) {
00281 batteryState->set(0);
00282 utility->publishBBItem(batteryCat, batteryState, scopeHost);
00283
00284 }
00285
00286
00287 cancelEvent(timeout);
00288 }
00289
00290
00291 else {
00292
00293 batteryState->set(residualCapacity);
00294
00295
00296 if ((lastPublishCapacity - residualCapacity)/capacity >= publishDelta) {
00297 utility->publishBBItem(batteryCat, batteryState, scopeHost);
00298 lastPublishCapacity = residualCapacity;
00299 }
00300 }
00301 residualVec.record(residualCapacity);
00302 }
00303
00304
00305
00306
00307
00308
00309
00310
00311 double SimpleBattery::getVoltage() {
00312 Enter_Method_Silent();
00313 return voltage;
00314 }
00315
00316
00317
00318
00319
00320
00321
00322 double SimpleBattery::estimateResidualAbs() {
00323 Enter_Method_Silent();
00324 double value = std::max(0.0, residualCapacity);
00325 return value;
00326 }
00327
00328
00329
00330
00331 double SimpleBattery::estimateResidualRelative() {
00332 Enter_Method_Silent();
00333 double value = std::max(0.0, residualCapacity);
00334 return value / nominalCapacity;
00335 }
00336
00337 void SimpleBattery::finish() {
00338
00339 deductAndCheck();
00340
00341 for (int i = 0; i < numDevices; i++) {
00342
00343 double total = 0;
00344 for (int j = 0; j < devices[i].numAccts; j++) {
00345 total += devices[i].accts[j];
00346 }
00347 debugEV<< "device " << i << " (" << devices[i].name << ") consumed "
00348 << total << " mW-s at" << endl;
00349
00350 for (int j = 0; j < devices[i].numAccts; j++) {
00351 debugEV << "activity " << j << ": " << devices[i].accts[j] << " mWs and "
00352 << devices[i].times[j] << "sec" << endl;
00353 }
00354
00355
00356 simtime_t sum = 0;
00357 for (int j = 0; j < devices[i].numAccts; j++)
00358 sum += devices[i].times[j];
00359 if (FWMath::round(sum.dbl() * 1000000) - FWMath::round(simTime().dbl() * 1000000) != 0)
00360 {
00361 EV << "WARNING: device " << devices[i].name << " total time " << sum
00362 << " != sim time " << simTime() << " (may not matter)" << endl;
00363 }
00364 }
00365
00366 cModule *statsModule = getParentModule()->getSubmodule("batteryStats");
00367 if (statsModule) {
00368 BatteryStats *batteryStats = check_and_cast<BatteryStats *>(statsModule);
00369 batteryStats->summary(capacity, residualCapacity, lifetime);
00370 batteryStats->detail(devices, numDevices);
00371 }
00372 else {
00373 error("No batteryStats module found, please check your Host.ned");
00374 }
00375
00376 BaseBattery::finish();
00377 }
00378
00379 SimpleBattery::~SimpleBattery() {
00380 cancelAndDelete(timeout);
00381 if (publishTime> 0)
00382 cancelAndDelete(publish);
00383
00384 delete [] devices;
00385
00386 delete batteryState;
00387 }
00388