/************************************************************************** * Copyright (C) 2006-2007 by Danny Kukawka * * , * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of version 2 of the GNU General Public License * * as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ /*! * \file hardware_battery.cpp * \brief In this file can be found the Battery related code. * \author Danny Kukawka, , * \date 2006-2007 */ #include "hardware_battery.h" // FOR REFERENCE // udi = '/org/freedesktop/Hal/devices/bme' // info.addons = { 'hald-addon-bme' } (string list) // maemo.charger.type = 'host 500 mA' (string) // maemo.charger.connection_status = 'connected' (string) // maemo.rechargeable.charging_status = 'on' (string) // maemo.rechargeable.positive_rate = true (bool) // battery.present = true (bool) // info.product = 'Battery (BME-HAL)' (string) // info.subsystem = 'unknown' (string) // battery.is_rechargeable = true (bool) // info.udi = '/org/freedesktop/Hal/devices/bme' (string) // battery.charge_level.unit = 'bars' (string) // battery.remaining_time = 7200 (0x1c20) (int) // battery.type = 'pda' (string) // battery.charge_level.percentage = 71 (0x47) (int) // battery.charge_level.design = 8 (0x8) (int) // battery.charge_level.capacity_state = 'ok' (string) // battery.rechargeable.is_discharging = false (bool) // battery.charge_level.last_full = 7 (0x7) (int) // battery.reporting.design = 1258 (0x4ea) (int) // battery.reporting.last_full = 867 (0x363) (int) // battery.reporting.current = 903 (0x387) (int) // battery.voltage.unit = 'mV' (string) // battery.voltage.design = 4200 (0x1068) (int) // info.category = 'battery' (string) // battery.voltage.current = 3947 (0xf6b) (int) // battery.remaining_time.calculate_per_time = false (bool) // info.parent = '/org/freedesktop/Hal/devices/computer' (string) // battery.charge_level.current = 7 (0x7) (int) // battery.rechargeable.is_charging = true (bool) // info.capabilities = { 'battery' } (string list) // battery.reporting.unit = 'mAh' (string) /*! The default constructor of the class Battery. */ Battery::Battery( TQString _udi ) { if (trace) kdDebug() << funcinfo << "IN , udi: " << udi << endl; m_hwdevices = TDEGlobal::hardwareDevices(); m_hwdevices->setBatteryUpdatesEnabled(true); udi = _udi; connect(m_hwdevices, TQT_SIGNAL(hardwareUpdated(TDEGenericDevice*)), this, TQT_SLOT(updateProperty(TDEGenericDevice*))); initialized = false; initDefault(); init(); kdDebugFuncOut(trace); } /*! The default destructor of the class Battery. */ Battery::~Battery() { kdDebugFuncIn(trace); } //! init a battery with default values void Battery::initDefault() { kdDebugFuncIn(trace); present = false; type = BAT_UNKNOWN; state = BAT_NORM; capacity_state = "ok"; charging_state = UNKNOWN_STATE; charge_level_unit = "mWh"; charge_level_current = 0; charge_level_lastfull = 0; charge_level_percentage = 0; design_capacity = 0; present_rate = 0; remaining_minutes = 0; serial = ""; warn_level = 12; low_level = 7; crit_level = 2; kdDebugFuncOut(trace); } //! initialize this battery object with values from HAL void Battery::init() { kdDebugFuncIn(trace); // read battery information from HAL if (resetUdi(udi)) { //udi is valid recheck(); //fills all values //ready here for now } else { //udi is invalid or is no battery state=BAT_HAL_ERROR; kdWarning() << "Warning: Battery::init cannot make use of udi " << udi << endl; } initialized = true; kdDebugFuncOut(trace); } //! rechecks only minimalistic set properties /*! * Will only recheck properties regarding current battery states/levels. */ void Battery::minRecheck() { kdDebugFuncIn(trace); // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::recheck couldn't find battery" << endl; kdDebugFuncOut(trace); return; } checkBatteryPresent(); if (!present) { kdDebug() << "No need to update other properties, battery not present." << endl; kdDebugFuncOut(trace); return; } else { checkCapacityState(); checkChargeLevelCurrent(); checkRemainingPercentage(); checkChargingState(); checkChargeLevelRate(); checkRemainingTime(); } kdDebugFuncOut(trace); } //! recheck all properties of the battery /*! * Check and set the properties of a battery or collect the information for all * primary batteries in one object. */ void Battery::recheck() { kdDebugFuncIn(trace); // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::recheck couldn't find battery" << endl; kdDebugFuncOut(trace); return; } checkBatteryPresent(); checkBatteryType(); if (!present) { kdDebug() << "Warning: No need to update properties, battery not present." << endl; kdDebugFuncOut(trace); return; } else { checkBatteryTechnology(); checkCapacityState(); checkChargeLevelCurrent(); checkChargeLevelLastfull(); checkRemainingPercentage(); checkChargingState(); checkChargeLevelUnit(); checkChargeLevelDesign(); checkChargeLevelRate(); checkRemainingTime(); } kdDebugFuncOut(trace); } // ---> query HAL for properties SECTION : START <---- //! to check battery.present /*! * function to update \ref present from property battery.present * \return boolean with the result of the operation * \retval true if the update was successfull * \retval false if the update couldn't be applied */ bool Battery::checkBatteryPresent () { kdDebugFuncIn(trace); bool _present = false; // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::checkBatteryPresent couldn't find battery" << endl; kdDebugFuncOut(trace); return false; } _present = bdevice->installed(); if (_present != present) { present = _present; // force depending changes if (_present) { // should be now present recheck(); } if (!_present) { //Uhhh, battery is not present, so we need to reset battery to default. initDefault(); checkBatteryType(); state = BAT_NONE; } if (initialized) { emit changedBatteryPresent(); emit changedBattery(); } } // also query the serial ... no need to do this in a extra place serial = bdevice->serialNumber(); kdDebugFuncOut(trace); return true; } //! to check battery.type /*! * function to update \ref type from property battery.type * \return boolean with the result of the operation * \retval true if the update was successfull * \retval false if the update couldn't be applied */ bool Battery::checkBatteryType () { kdDebugFuncIn(trace); TQString tmp_qstring; // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::checkBatteryType couldn't find battery" << endl; kdDebugFuncOut(trace); return false; } // FIXME // How can we get battery type from TDE HW library (i.e. how to get type from sysfs)? // For now just report any batteries as primary... type = BAT_PRIMARY; return true; } //! to check battery.technology /*! * function to update \ref technology from property battery.technology * \return boolean with the result of the operation * \retval true if the update was successfull * \retval false if the update couldn't be applied */ bool Battery::checkBatteryTechnology () { kdDebugFuncIn(trace); TQString tmp_qstring; // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::checkBatteryTechnology couldn't find battery" << endl; kdDebugFuncOut(trace); return false; } if (!present) { kdWarning() << "No need to update property, battery not present." << endl; kdDebugFuncOut(trace); return false; } tmp_qstring = bdevice->technology(); if (!tmp_qstring.isEmpty()) { technology = TQString(tmp_qstring); } else { technology = TQString("UNKNOWN"); } kdDebugFuncOut(trace); return true; } //! to check battery.charge_level.capacity_state /*! * function to update \ref capacity_state from battery.charge_level.capacity_state * \return boolean with the result of the operation * \retval true if the update was successfull * \retval false if the update couldn't be applied */ bool Battery::checkCapacityState () { kdDebugFuncIn(trace); TQString tmp_qstring; // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::checkCapacityState couldn't find battery" << endl; kdDebugFuncOut(trace); return false; } if (!present) { kdWarning() << "No need to update property, battery not present." << endl; kdDebugFuncOut(trace); return false; } capacity_state = "unknown"; TDEBatteryStatus::TDEBatteryStatus batteryStatus = bdevice->status(); if (batteryStatus == TDEBatteryStatus::Charging) { capacity_state = "charging"; } if (batteryStatus == TDEBatteryStatus::Discharging) { capacity_state = "discharging"; } if (batteryStatus == TDEBatteryStatus::Full) { capacity_state = "full"; } kdDebugFuncOut(trace); return true; } //! to check battery.charge_level.current /*! * function to update \ref charge_level_current from property battery.charge_level.current * \return boolean with the result of the operation * \retval true if the update was successfull * \retval false if the update couldn't be applied */ bool Battery::checkChargeLevelCurrent () { kdDebugFuncIn(trace); // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::checkChargeLevelCurrent couldn't find battery" << endl; kdDebugFuncOut(trace); return false; } if (!present) { kdWarning() << "No need to update property, battery not present." << endl; kdDebugFuncOut(trace); return false; } // FIXME VERIFY CORRECTNESS // what does tdepowersave expect to see in charge_level_current (battery.charge_level.current)? charge_level_current = bdevice->energy(); if (charge_level_current < 0) { //overflow? charge_level_current = 0; } kdDebugFuncOut(trace); return true; } //! to check battery.charge_level.last_full /*! * function to update \ref charge_level_lastfull from property battery.charge_level.last_full * \return boolean with the result of the operation * \retval true if the update was successfull * \retval false if the update couldn't be applied */ bool Battery::checkChargeLevelLastfull () { kdDebugFuncIn(trace); // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::checkChargeLevelLastfull couldn't find battery" << endl; kdDebugFuncOut(trace); return false; } if (!present) { kdWarning() << "No need to update property, battery not present." << endl; kdDebugFuncOut(trace); return false; } // FIXME VERIFY CORRECTNESS // what does tdepowersave expect to see in charge_level_lastfull (battery.charge_level.last_full)? charge_level_lastfull = bdevice->maximumEnergy(); if (charge_level_lastfull < charge_level_current ) { //possible overflow? charge_level_lastfull = charge_level_current; } kdDebugFuncOut(trace); return true; } //! to check battery.charge_level.rate /*! * function to update \ref present_rate from property battery.charge_level.rate * \return boolean with the result of the operation * \retval true if the update was successfull * \retval false if the update couldn't be applied */ bool Battery::checkChargeLevelRate () { kdDebugFuncIn(trace); // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::checkChargeLevelRate couldn't find battery" << endl; kdDebugFuncOut(trace); return false; } if (!present) { kdWarning() << "No need to update property, battery not present." << endl; kdDebugFuncOut(trace); return false; } int _rate = present_rate; // FIXME VERIFY CORRECTNESS // what does tdepowersave expect to see in present_rate (battery.charge_level.rate)? present_rate = bdevice->dischargeRate(); if (present_rate < 0 ) present_rate = 0; if (present_rate != _rate) emit changedBattery(); kdDebugFuncOut(trace); return true; } //! to check battery.charge_level.unit /*! * function to update \ref charge_level_unit from property battery.charge_level.unit * \return boolean with the result of the operation * \retval true if the update was successfull * \retval false if the update couldn't be applied */ bool Battery::checkChargeLevelUnit () { kdDebugFuncOut(trace); // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::checkChargeLevelUnit couldn't find battery" << endl; kdDebugFuncOut(trace); return false; } if (!present) { kdWarning() << "No need to update property, battery not present." << endl; kdDebugFuncOut(trace); return false; } // Power supply energy informations in sysfs are always in uWh. // https://www.kernel.org/doc/Documentation/power/power_supply_class.txt // TDE hardware library internally uses Wh. // Since charge level unit are always Wh. charge_level_unit = "Wh"; kdDebugFuncOut(trace); return false; } //! to check battery.charge_level.design /*! * function to update \ref design_capacity from property battery.charge_level.design * \return boolean with the result of the operation * \retval true if the update was successfull * \retval false if the update couldn't be applied */ bool Battery::checkChargeLevelDesign () { kdDebugFuncIn(trace); // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::checkChargeLevelDesign couldn't find battery" << endl; kdDebugFuncOut(trace); return false; } if (!present) { kdWarning() << "No need to update property, battery not present." << endl; kdDebugFuncOut(trace); return false; } // FIXME VERIFY CORRECTNESS // what does tdepowersave expect to see in design_capacity (battery.charge_level.last_full)? design_capacity = bdevice->maximumDesignEnergy(); if (design_capacity < 0) { design_capacity = 0; } kdDebugFuncOut(trace); return true; } //! to check battery.charge_level.percentage /*! * function to update \ref charge_level_percentage from property battery.charge_level.percentage * \return boolean with the result of the operation * \retval true if the update was successfull * \retval false if the update couldn't be applied */ bool Battery::checkRemainingPercentage () { kdDebugFuncIn(trace); bool ret = false; int _val = 0; int _state = -1; // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::checkRemainingPercentage couldn't find battery" << endl; kdDebugFuncOut(trace); return false; } if (!present) { kdWarning() << "No need to update property, battery not present." << endl; kdDebugFuncOut(trace); return false; } _val = bdevice->chargePercent(); if (_val > 100) { _val = 100; } else if (_val < 0) { _val = 0; } ret = true; if (charge_level_percentage != _val) { if (initialized) { emit changedBatteryPercentage(); emit changedBattery(); } charge_level_percentage = _val; } //battery state if (charge_level_percentage <= crit_level) { //we are now in critical level _state = BAT_CRIT; } else if (charge_level_percentage <= low_level) { //we are now in a low level _state = BAT_LOW; } else if (charge_level_percentage <= warn_level) { //we are now in warning state _state = BAT_WARN; } else if (state != BAT_NONE) { _state = BAT_NORM; } else { _state = BAT_NONE; } if (state != _state) { if (initialized) { if (_state == (BAT_CRIT || BAT_LOW || BAT_WARN)) emit changedBatteryWarnState(_state); else if (state == (BAT_CRIT || BAT_LOW || BAT_WARN)) emit changedBatteryWarnState(_state); else emit changedBatteryState(); emit changedBattery(); } state = _state; } kdDebugFuncOut(trace); return ret; } //! to check battery.remaining_time /*! * function to update \ref remaining_minutes from property battery.remaining_time * \return boolean with the result of the operation * \retval true if the update was successfull * \retval false if the update couldn't be applied */ bool Battery::checkRemainingTime () { kdDebugFuncIn(trace); int _min = 0; bool _ret = false; // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::checkRemainingTime couldn't find battery" << endl; kdDebugFuncOut(trace); return false; } if (!present) { kdWarning() << "No need to update property, battery not present." << endl; kdDebugFuncOut(trace); return false; } _min = bdevice->timeRemaining(); _min /= 60; _ret = true; if (remaining_minutes != _min) { if (initialized) { emit changedBatteryTime(); emit changedBattery(); } remaining_minutes = _min; } kdDebugFuncOut(trace); return _ret; } //! to check battery.rechargeable.is_* /*! * function to update \ref charging_state from property battery.rechargeable.is_* * \return boolean with the result of the operation * \retval true if the update was successfull * \retval false if the update couldn't be applied */ bool Battery::checkChargingState () { kdDebugFuncIn(trace); bool tmp_bool = false; bool tmp_bool2 = false; bool _ret = false; int _c_state = -1; // First make sure the battery object is still available TDEBatteryDevice* bdevice = dynamic_cast(m_hwdevices->findByUniqueID(udi)); if (!bdevice) { //grr... no luck kdError() << "Battery::checkChargingState couldn't find battery" << endl; kdDebugFuncOut(trace); return false; } if (!present) { kdWarning() << "No need to update property, battery not present." << endl; kdDebugFuncOut(trace); return false; } tmp_bool = (bdevice->status() == TDEBatteryStatus::Charging); tmp_bool2 = (bdevice->status() == TDEBatteryStatus::Discharging); if (tmp_bool && !tmp_bool2) { _c_state = CHARGING; } else if (tmp_bool2 && !tmp_bool) { _c_state = DISCHARGING; } else { _c_state = UNKNOWN_STATE; } _ret = true; if (charging_state != _c_state) { if (initialized) { emit changedBatteryChargingState(); emit changedBattery(); } charging_state = _c_state; } kdDebugFuncOut(trace); return _ret; } // ---> query HAL for properties SECTION : END <---- //! to recheck a special value for a HAL event /*! * Check for the given property new values from HAL and set them to * the battery variables. * \param device TDEGenericDevice */ void Battery::updateProperty(TDEGenericDevice* device) { kdDebugFuncIn(trace); if (device->uniqueID() == udi) { recheck(); } kdDebugFuncOut(trace); } //! Resets the current HAL udi used by the one given /*! * The given TQString will be (checked and) used as new HAL udi for the battery. * But don't forget to do a recheck of the battery afterwards. * \param _udi TQString with the UDI to reset * \return boolean with the result of the operation * \retval true if reset was successfull * \retval false if reset couldn't be applied */ bool Battery::resetUdi(TQString _udi) { kdDebugFuncIn(trace); // FIXME // What does this function do outside of HAL!?!? Should it even exist any more? bool tmp_result=true; kdDebugFuncOut(trace); return tmp_result; } // ---> write private members SECTION : START <---- //! sets the chargelevel in percent when battery should go into state warning void Battery::setWarnLevel(int _warn_level) { kdDebugFuncIn(trace); if (_warn_level < low_level) { kdError() << "Refuse requested level: " << _warn_level << " as it is smaller than the LowLevel: " << low_level << endl; } else { warn_level = _warn_level; } kdDebugFuncOut(trace); } //! sets the chargelevel in percent when battery should go into state low void Battery::setLowLevel(int _low_level) { kdDebugFuncIn(trace); if (_low_level < crit_level || _low_level > warn_level) { kdError() << "Refuse requested level: " << _low_level << " as it is not between WarnLevel: " << warn_level << " and CritLevel: " << crit_level << endl; } else { low_level = _low_level; } kdDebugFuncOut(trace); } //! sets the chargelevel in percent when battery should go into state critical void Battery::setCritLevel(int _crit_level) { kdDebugFuncIn(trace); if (_crit_level > low_level) { kdError() << "Refuse requested level: " << _crit_level << " as it is bigger than LowLevel: " << low_level << endl; } else { crit_level = _crit_level; } kdDebugFuncOut(trace); } // ---> write private members SECTION : END <---- // ---> get private members SECTION : START <---- //! reports the HAL udi of this battery TQString Battery::getUdi() const { return TQString(udi); } //! reports the battery type int Battery::getType() const { return type; } //! gives the name of this battery technology TQString Battery::getTechnology() const { return TQString(technology); } //! tells the current batterystate as enum BAT_STATE_ int Battery::getState() const { return state; } //! estimates the remaining minutes until fully charged/discharged int Battery::getRemainingMinutes() const { return remaining_minutes; } //! current charging/discharging rate int Battery::getPresentRate() const { return present_rate; } //! get availability of this battery bool Battery::isPresent() { return present; } //! maximum capacity of this battery by design int Battery::getDesignCapacity() const { return design_capacity; } //! current charging state as enum BAT_CHARG_STATE int Battery::getChargingState() const { return charging_state; } //! reports the physical unit of values like DesignCapacity, PresentRate and Lastfull TQString Battery::getChargelevelUnit() const { return TQString(charge_level_unit); } //! reports current chargelevel in percentage int Battery::getPercentage() const { return charge_level_percentage; } //! reports last full capacity of this battery when fully charged int Battery::getLastfull() const { return charge_level_lastfull; } //! reports current chargelevel in units reported by getChargelevelUnit() int Battery::getCurrentLevel() const { return charge_level_current; } //! reports HAL capacity_state value TQString Battery::getCapacityState() const { return TQString(capacity_state); } //! reports the chargelevel in percent when battery goes to state warning int Battery::getWarnLevel() const { return warn_level; } //! reports the chargelevel in percent when battery goes to state low int Battery::getLowLevel() const { return low_level; } //! reports the chargelevel in percent when battery goes to state critical int Battery::getCritLevel() const { return crit_level; } //some convenience methods //! check if the battery is currently charged bool Battery::isCharging() { return (charging_state == CHARGING); } //! check if the battery gets currently discharged bool Battery::isDischarging() { return (charging_state == DISCHARGING); } //! check it this is a primary battery bool Battery::isPrimary() const { return (type == BAT_PRIMARY); } //! check if the battery state is ok/normal bool Battery::isOk() { return (state == BAT_NORM); } //! check if the battery is in warning level/state bool Battery::isWarning() { return (state == BAT_WARN); } //! check if the battery is in a low chargingstate bool Battery::isLow() { return (state == BAT_LOW); } //! check if the battery level is critical bool Battery::isCritical() { return (state == BAT_CRIT); } // ---> get private members SECTION : START <---- #include "hardware_battery.moc"