blob: 66cb1cd6d85c52b520ae268289a46094e7fbf56d [file] [log] [blame]
/*
* Copyright (c) 2011 Anssi Hannula
*
* This file is part of PowerTOP
*
* This program file is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; version 2 of the License.
*
* 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 in a file named COPYING; if not, write to the
* Free Software Foundation, Inc,
* 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
* or just google for it.
*
* Authors:
* Anssi Hannula <anssi.hannula@iki.fi>
*/
#include "measurement.h"
#include "sysfs.h"
#include "../lib.h"
#include <string.h>
#include <stdio.h>
sysfs_power_meter::sysfs_power_meter(const char *power_supply_name)
{
rate = 0.0;
capacity = 0.0;
strncpy(name, power_supply_name, sizeof(name));
}
bool sysfs_power_meter::get_sysfs_attr(const char *attribute, int *value)
{
char filename[4096];
bool ok;
snprintf(filename, sizeof(filename), "/sys/class/power_supply/%s/%s", name, attribute);
*value = read_sysfs(filename, &ok);
return ok;
}
bool sysfs_power_meter::is_present()
{
int present = 0;
if (!get_sysfs_attr("present", &present))
return true; /* assume always present */
return present;
}
double sysfs_power_meter::get_voltage()
{
int voltage;
if (!get_sysfs_attr("voltage_now", &voltage))
return -1.0;
/* µV to V */
return voltage / 1000000.0;
}
bool sysfs_power_meter::set_rate_from_power()
{
int power;
if (!get_sysfs_attr("power_now", &power))
return false;
/* µW to W */
rate = power / 1000000.0;
return true;
}
bool sysfs_power_meter::set_rate_from_current(double voltage)
{
int current;
if (!get_sysfs_attr("current_now", &current))
return false;
/* current: µA
* voltage: V
* rate: W */
rate = (current / 1000000.0) * voltage;
return true;
}
bool sysfs_power_meter::set_capacity_from_energy()
{
int energy;
if (!get_sysfs_attr("energy_now", &energy))
return false;
/* µWh to J */
capacity = energy / 1000000.0 * 3600.0;
return true;
}
bool sysfs_power_meter::set_capacity_from_charge(double voltage)
{
int charge;
if (!get_sysfs_attr("charge_now", &charge))
return false;
/* charge: µAh
* voltage: V
* capacity: J */
capacity = (charge / 1000000.0) * voltage * 3600.0;
return true;
}
void sysfs_power_meter::measure()
{
bool got_rate = false;
bool got_capacity = false;
rate = 0.0;
capacity = 0.0;
if (!is_present())
return;
if (read_sysfs_string("/sys/class/power_supply/%s/status", name) != "Discharging")
return;
got_rate = set_rate_from_power();
got_capacity = set_capacity_from_energy();
if (!got_rate || !got_capacity) {
double voltage = get_voltage();
if (voltage < 0.0)
return;
if (!got_rate)
set_rate_from_current(voltage);
if (!got_capacity)
set_capacity_from_charge(voltage);
}
}
void sysfs_power_meter::end_measurement(void)
{
measure();
}
void sysfs_power_meter::start_measurement(void)
{
/* Battery state is generally a lagging indication, lets only measure at the end */
}