All Classes Namespaces Files Functions Variables Enumerations Enumerator
libs/system/BatteryState.cpp
Go to the documentation of this file.
00001 
00010 #include "BatteryState.h"
00011 #include "DetectOS.h"
00012 #if defined(WINDOWS_OS)
00013 #include <windows.h>
00014 #else
00015 #include "split.h"
00016 #include <algorithm>
00017 #include <string>
00018 #include <fstream>
00019 #include <cstdlib>
00020 #endif
00021 
00022 using namespace qrk;
00023 using namespace std;
00024 
00025 
00026 #if defined(WINDOWS_OS)
00027 struct BatteryState::pImpl
00028 {
00029     bool isAvailable(void)
00030     {
00031         SYSTEM_POWER_STATUS status;
00032         if (! GetSystemPowerStatus(&status)) {
00033             return false;
00034         }
00035         return (status.BatteryLifePercent == 255) ? false : true;
00036     }
00037 
00038 
00039     bool isCharging(void)
00040     {
00041         SYSTEM_POWER_STATUS status;
00042         if (! GetSystemPowerStatus(&status)) {
00043             return false;
00044         }
00045         return (static_cast<int>(status.ACLineStatus) == 1) ? true : false;
00046     }
00047 
00048 
00049     size_t remainingPercent(void)
00050     {
00051         SYSTEM_POWER_STATUS status;
00052         if (! GetSystemPowerStatus(&status)) {
00053             return 0;
00054         }
00055         return status.BatteryLifePercent;
00056     }
00057 
00058 
00059     size_t remainingSecond(void)
00060     {
00061         SYSTEM_POWER_STATUS status;
00062         if (! GetSystemPowerStatus(&status)) {
00063             return 0;
00064         }
00065         return max(0, static_cast<int>(status.BatteryLifeTime));
00066     }
00067 };
00068 #else
00069 
00070 struct BatteryState::pImpl
00071 {
00072     bool is_available_;
00073     size_t full_capacity_;
00074     string state_file_;
00075     string info_file_;
00076 
00077 
00078     pImpl(void) : is_available_(false), full_capacity_(1)
00079     {
00080         // BAT0, BAT1 を順番に試す
00081         for (size_t id = 0; id < 2; ++id) {
00082             char buffer[] = "BAT0";
00083             snprintf(buffer, sizeof(buffer), "BAT%d", id);
00084 
00085             state_file_ = "/proc/acpi/battery/" + string(buffer) + "/state";
00086             info_file_ = "/proc/acpi/battery/" + string(buffer) + "/info";
00087 
00088             if (loadFullCapacity()) {
00089                 break;
00090             }
00091         }
00092     }
00093 
00094 
00095     bool matchData(string& value, const char* file, const char* pattern) const
00096     {
00097         ifstream fin(file);
00098         if (! fin.is_open()) {
00099             return false;
00100         }
00101 
00102         // トークンの区切りを ':' とし、得られた結果からは空白を除去して返す
00103         string line;
00104         while (getline(fin, line)) {
00105             vector<string> tokens;
00106             if (split(tokens, line, ":") >= 2) {
00107                 if (! tokens[0].compare(pattern)) {
00108                     string& token = tokens[1];
00109                     size_t first_index = 0;
00110                     while (token[first_index] == ' ') {
00111                         ++first_index;
00112                     }
00113                     value = &token[first_index];
00114                     return true;
00115                 }
00116             }
00117         }
00118         return false;
00119     }
00120 
00121 
00122     bool matchData(size_t& value, const char* file, const char* pattern) const
00123     {
00124         string string_value;
00125         if (! matchData(string_value, file, pattern)) {
00126             return false;
00127         }
00128 
00129         value = atoi(string_value.c_str());
00130         return true;
00131     }
00132 
00133 
00134     bool loadFullCapacity(void)
00135     {
00136         // /proc/acpi/battery/BATx/info ファイルの "last full capacity"
00137         // を読み出す
00138         if ((matchData(full_capacity_,
00139                        info_file_.c_str(), "last full capacity")) &&
00140             (full_capacity_ > 0)) {
00141             is_available_ = true;
00142             return true;
00143         }
00144 
00145         return false;
00146     }
00147 
00148 
00149     bool isAvailable(void) const
00150     {
00151         return is_available_;
00152     }
00153 
00154 
00155     bool isCharging(void) const
00156     {
00157         if (! is_available_) {
00158             return false;
00159         }
00160 
00161         // 電源が接続されていないときに false を返す
00162         // /proc/acpi/battery/BATx/state ファイルの "charging state" を読み出す
00163         string state;
00164         if (matchData(state, state_file_.c_str(), "charging state") &&
00165             ((! state.compare("charged")) || (! state.compare("charging")))) {
00166             return true;
00167         }
00168 
00169         return false;
00170     }
00171 
00172 
00173     size_t remainingPercent(void) const
00174     {
00175         if (! is_available_) {
00176             return 0;
00177         }
00178 
00179         // "/proc/acpi/battery/BATx/state" ファイルの
00180         // "remaining capacity" を読み出し full_capacity_ から残量を計算する
00181         size_t remaining_capacity = 0;
00182         if (! matchData(remaining_capacity,
00183                         state_file_.c_str(), "remaining capacity")) {
00184             return 0;
00185         }
00186 
00187         size_t percent = min(static_cast<size_t>(100),
00188                              100 * remaining_capacity / full_capacity_);
00189 
00190         return percent;
00191     }
00192 
00193 
00194     size_t remainingSecond(void) const
00195     {
00196         if (! is_available_) {
00197             return 0;
00198         }
00199 
00200         if (isCharging()) {
00201             return 0;
00202         }
00203 
00204         // "/proc/acpi/battery/BATx/state" ファイルの
00205         // "present rate" [mW] と "remaining capacity" [mWh] を読み出し、
00206         // バッテリーが使える時間を計算する
00207         size_t present_rate = 0;
00208         if (! matchData(present_rate, state_file_.c_str(), "present rate")) {
00209             return 0;
00210         }
00211 
00212         size_t remaining_capacity = 0;
00213         if (! matchData(remaining_capacity,
00214                         state_file_.c_str(), "remaining capacity")) {
00215             return 0;
00216         }
00217 
00218         size_t second =
00219             60 * 60 * remaining_capacity / max(present_rate,
00220                                                static_cast<size_t>(1));
00221         return second;
00222     }
00223 };
00224 #endif
00225 
00226 
00227 BatteryState::BatteryState(void) : pimpl(new pImpl)
00228 {
00229 }
00230 
00231 
00232 BatteryState::~BatteryState(void)
00233 {
00234 }
00235 
00236 
00237 bool BatteryState::isAvailable(void) const
00238 {
00239     return pimpl->isAvailable();
00240 }
00241 
00242 
00243 bool BatteryState::isCharging(void) const
00244 {
00245     return pimpl->isCharging();
00246 }
00247 
00248 
00249 size_t BatteryState::remainingPercent(void) const
00250 {
00251     return pimpl->remainingPercent();
00252 }
00253 
00254 
00255 size_t BatteryState::remainingSecond(void) const
00256 {
00257     return pimpl->remainingSecond();
00258 }