diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 20:00:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 20:00:20 +0000 |
commit | fcb4cb5c3d0fec0fede160d565134d553d783fb2 (patch) | |
tree | 7be42535554ca6badc1847d83ef123f4dc3c5506 /src/measurement | |
parent | Initial commit. (diff) | |
download | powertop-upstream.tar.xz powertop-upstream.zip |
Adding upstream version 2.15.upstream/2.15upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/measurement')
-rw-r--r-- | src/measurement/acpi.cpp | 213 | ||||
-rw-r--r-- | src/measurement/acpi.h | 46 | ||||
-rw-r--r-- | src/measurement/extech.cpp | 354 | ||||
-rw-r--r-- | src/measurement/extech.h | 51 | ||||
-rw-r--r-- | src/measurement/measurement.cpp | 188 | ||||
-rw-r--r-- | src/measurement/measurement.h | 71 | ||||
-rw-r--r-- | src/measurement/opal-sensors.cpp | 48 | ||||
-rw-r--r-- | src/measurement/opal-sensors.h | 42 | ||||
-rw-r--r-- | src/measurement/sysfs.cpp | 160 | ||||
-rw-r--r-- | src/measurement/sysfs.h | 55 |
10 files changed, 1228 insertions, 0 deletions
diff --git a/src/measurement/acpi.cpp b/src/measurement/acpi.cpp new file mode 100644 index 0000000..572852c --- /dev/null +++ b/src/measurement/acpi.cpp @@ -0,0 +1,213 @@ +/* + * Copyright 2010, Intel Corporation + * + * 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: + * Arjan van de Ven <arjan@linux.intel.com> + */ +#include "measurement.h" +#include "acpi.h" +#include <iostream> +#include <fstream> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include "../lib.h" + +using namespace std; + +acpi_power_meter::acpi_power_meter(const char *acpi_name) +{ + rate = 0.0; + capacity = 0.0; + voltage = 0.0; + pt_strcpy(battery_name, acpi_name); +} + +/* +present: yes +capacity state: ok +charging state: discharging +present rate: 8580 mW +remaining capacity: 34110 mWh +present voltage: 12001 mV +*/ + +void acpi_power_meter::measure(void) +{ + char filename[PATH_MAX]; + char line[4096]; + ifstream file; + + double _rate = 0; + double _capacity = 0; + double _voltage = 0; + + char rate_units[16]; + char capacity_units[16]; + char voltage_units[16]; + + rate_units[0] = 0; + capacity_units[0] = 0; + voltage_units[0] = 0; + + rate = 0; + voltage = 0; + capacity = 0; + + snprintf(filename, sizeof(filename), "/proc/acpi/battery/%s/state", battery_name); + + file.open(filename, ios::in); + if (!file) + return; + + while (file) { + char *c; + file.getline(line, sizeof(line)); + + if (strstr(line, "present:") && (strstr(line, "yes") == NULL)) { + return; + } + if (strstr(line, "charging state:") && (strstr(line, "discharging") == NULL)) { + return; /* not discharging */ + } + if (strstr(line, "present rate:")) { + c = strchr(line, ':'); + c++; + while (*c == ' ') c++; + _rate = strtoull(c, NULL, 10); + c = strchr(c, ' '); + if (c) { + c++; + pt_strcpy(rate_units, c); + } else { + _rate = 0; + strcpy(rate_units, "Unknown"); + } + + } + if (strstr(line, "remaining capacity:")) { + c = strchr(line, ':'); + c++; + while (*c == ' ') c++; + _capacity = strtoull(c, NULL, 10); + c = strchr(c, ' '); + if (c) { + c++; + pt_strcpy(capacity_units, c); + } else { + _capacity = 0; + strcpy(capacity_units, "Unknown"); + } + } + if (strstr(line, "present voltage:")) { + c = strchr(line, ':'); + c++; + while (*c == ' ') c++; + _voltage = strtoull(c, NULL, 10); + c = strchr(c, ' '); + if (c) { + c++; + pt_strcpy(voltage_units, c); + } else { + _voltage = 0; + strcpy(voltage_units, "Unknown"); + } + } + } + file.close(); + + /* BIOS report random crack-inspired units. Lets try to get to the Si-system units */ + + if (strcmp(voltage_units, "mV") == 0) { + _voltage = _voltage / 1000.0; + strcpy(voltage_units, "V"); + } + + if (strcmp(rate_units, "mW") == 0) { + _rate = _rate / 1000.0; + strcpy(rate_units, "W"); + } + + if (strcmp(rate_units, "mA") == 0) { + _rate = _rate / 1000.0; + strcpy(rate_units, "A"); + } + + if (strcmp(capacity_units, "mAh") == 0) { + _capacity = _capacity / 1000.0; + strcpy(capacity_units, "Ah"); + } + if (strcmp(capacity_units, "mWh") == 0) { + _capacity = _capacity / 1000.0; + strcpy(capacity_units, "Wh"); + } + if (strcmp(capacity_units, "Wh") == 0) { + _capacity = _capacity * 3600.0; + strcpy(capacity_units, "J"); + } + + + if (strcmp(capacity_units, "Ah") == 0 && strcmp(voltage_units, "V") == 0) { + _capacity = _capacity * 3600.0 * _voltage; + strcpy(capacity_units, "J"); + } + + if (strcmp(rate_units, "A") == 0 && strcmp(voltage_units, "V")==0 ) { + _rate = _rate * _voltage; + strcpy(rate_units, "W"); + } + + + + + if (strcmp(capacity_units, "J") == 0) + capacity = _capacity; + else + capacity = 0.0; + + if (strcmp(rate_units, "W")==0) + rate = _rate; + else + rate = 0.0; + + if (strcmp(voltage_units, "V")==0) + voltage = _voltage; + else + voltage = 0.0; +} + + +void acpi_power_meter::end_measurement(void) +{ + measure(); +} + +void acpi_power_meter::start_measurement(void) +{ + /* ACPI battery state is a lagging indication, lets only measure at the end */ +} + + +double acpi_power_meter::power(void) +{ + return rate; +} diff --git a/src/measurement/acpi.h b/src/measurement/acpi.h new file mode 100644 index 0000000..25bbe04 --- /dev/null +++ b/src/measurement/acpi.h @@ -0,0 +1,46 @@ +/* + * Copyright 2010, Intel Corporation + * + * 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: + * Arjan van de Ven <arjan@linux.intel.com> + */ +#ifndef __INCLUDE_GUARD_ACPI_H +#define __INCLUDE_GUARD_ACPI_H + +#include "measurement.h" + +class acpi_power_meter: public power_meter { + char battery_name[256]; + + double capacity; + double rate; + double voltage; + void measure(void); +public: + acpi_power_meter(const char *_battery_name); + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double power(void); + virtual double dev_capacity(void) { return capacity; }; +}; + +#endif diff --git a/src/measurement/extech.cpp b/src/measurement/extech.cpp new file mode 100644 index 0000000..867aca7 --- /dev/null +++ b/src/measurement/extech.cpp @@ -0,0 +1,354 @@ +/* + * extech - Program for controlling the extech Device + * This file is part of PowerTOP + * + * Based on earlier client by Patrick Mochel for Wattsup Pro device + * Copyright (c) 2005 Patrick Mochel + * Copyright (c) 2006 Intel Corporation + * Copyright (c) 2011 Intel Corporation + * + * Authors: + * Patrick Mochel + * Venkatesh Pallipadi + * Arjan van de Ven + * + * Thanks to Rajiv Kapoor for finding out the DTR, RTS line bits issue below + * Without that this program would never work. + * + * + * 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. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <termios.h> +#include <ctype.h> +#include <getopt.h> +#include <time.h> +#include <signal.h> + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <sys/stat.h> + +#include "measurement.h" +#include "extech.h" +#include "../lib.h" +#include <iostream> +#include <fstream> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +using namespace std; + +struct packet { + char buf[256]; + char op[32]; + double watts; + int len; +}; + + +static int open_device(const char *device_name) +{ + struct stat s; + int ret; + + ret = stat(device_name, &s); + if (ret < 0) + return -1; + + if (!S_ISCHR(s.st_mode)) + return -1; + + ret = access(device_name, R_OK | W_OK); + if (ret) + return -1; + + ret = open(device_name, O_RDWR | O_NONBLOCK | O_NOCTTY); + if (ret < 0) + return -1; + + return ret; +} + + +static int setup_serial_device(int dev_fd) +{ + struct termios t; + int ret; + int flgs; + + ret = tcgetattr(dev_fd, &t); + if (ret) + return ret; + + cfmakeraw(&t); + cfsetispeed(&t, B9600); + cfsetospeed(&t, B9600); + tcflush(dev_fd, TCIFLUSH); + + t.c_iflag = IGNPAR; + t.c_cflag = B9600 | CS8 | CREAD | CLOCAL; + t.c_oflag = 0; + t.c_lflag = 0; + t.c_cc[VMIN] = 2; + t.c_cc[VTIME] = 0; + + t.c_iflag &= ~(IXON | IXOFF | IXANY); + t.c_oflag &= ~(IXON | IXOFF | IXANY); + + ret = tcsetattr(dev_fd, TCSANOW, &t); + + if (ret) + return ret; + + /* + * Root caused by Rajiv Kapoor. Without this extech reads + * will fail + */ + + /* get DTR and RTS line bits settings */ + ioctl(dev_fd, TIOCMGET, &flgs); + + /* set DTR to 1 and RTS to 0 */ + flgs |= TIOCM_DTR; + flgs &= ~TIOCM_RTS; + ioctl(dev_fd, TIOCMSET, &flgs); + + return 0; +} + + +static unsigned int decode_extech_value(unsigned char byt3, unsigned char byt4, char *a) +{ + unsigned int input = ((unsigned int)byt4 << 8) + byt3; + unsigned int i; + unsigned int idx; + unsigned char revnum[] = { 0x0, 0x8, 0x4, 0xc, + 0x2, 0xa, 0x6, 0xe, + 0x1, 0x9, 0x5, 0xd, + 0x3, 0xb, 0x7, 0xf}; + unsigned char revdec[] = { 0x0, 0x2, 0x1, 0x3}; + + unsigned int digit_map[] = {0x2, 0x3c, 0x3c0, 0x3c00}; + unsigned int digit_shift[] = {1, 2, 6, 10}; + + unsigned int sign; + unsigned int decimal; + + /* this is basically BCD encoded floating point... but kinda weird */ + + decimal = (input & 0xc000) >> 14; + decimal = revdec[decimal]; + + sign = input & 0x1; + + idx = 0; + if (sign) + a[idx++] = '+'; + else + a[idx++] = '-'; + + /* first digit is only one or zero */ + a[idx] = '0'; + if ((input & digit_map[0]) >> digit_shift[0]) + a[idx] += 1; + + idx++; + /* Reverse the remaining three digits and store in the array */ + for (i = 1; i < 4; i++) { + int dig = ((input & digit_map[i]) >> digit_shift[i]); + dig = revnum[dig]; + if (dig > 0xa) + goto error_exit; + + a[idx++] = '0' + dig; + } + + /* Fit the decimal point where appropriate */ + for (i = 0; i < decimal; i++) + a[idx - i] = a[idx - i - 1]; + + a[idx - decimal] = '.'; + a[++idx] = '0'; + a[++idx] = '\0'; + + return 0; +error_exit: + return -1; +} + +static int parse_packet(struct packet * p) +{ + int i; + int ret; + + p->buf[p->len] = '\0'; + + /* + * First character in 5 character block should be '02' + * Fifth character in 5 character block should be '03' + */ + for (i = 0; i < 4; i++) { + if (p->buf[i * 0] != 2 || p->buf[i * 0 + 4] != 3) { + printf("Invalid packet\n"); + return -1; + } + } + + for (i = 0; i < 1; i++) { + ret = decode_extech_value(p->buf[5 * i + 2], + p->buf[5 * i + 3], + &(p->op[8 * i])); + if (ret) { + printf("Invalid packet, conversion failed\n"); + return -1; + } + p->watts = strtod( &(p->op[8 * i]), NULL); + } + return 0; +} + + +static double extech_read(int fd) +{ + struct packet p; + fd_set read_fd; + struct timeval tv; + int ret; + + if (fd < 0) + return 0.0; + + FD_ZERO(&read_fd); + FD_SET(fd, &read_fd); + + tv.tv_sec = 0; + tv.tv_usec = 500000; + + memset(&p, 0, sizeof(p)); + + ret = select(fd + 1, &read_fd, NULL, NULL, &tv); + if (ret <= 0) + return -1; + + ret = read(fd, &p.buf, 250); + if (ret < 0) + return ret; + p.len = ret; + + if (!parse_packet(&p)) + return p.watts; + + return -1000.0; +} + +extech_power_meter::extech_power_meter(const char *extech_name) +{ + rate = 0.0; + pt_strcpy(dev_name, extech_name); + int ret; + + fd = open_device(dev_name); + if (fd < 0) + return; + + ret = setup_serial_device(fd); + if (ret) { + close(fd); + fd = -1; + return; + } +} + + +void extech_power_meter::measure(void) +{ + /* trigger the extech to send data */ + if(write(fd, " ", 1) == -1) + printf("Error: %s\n", strerror(errno)); + + rate = extech_read(fd); + +} + +void extech_power_meter::sample(void) +{ + ssize_t ret; + struct timespec tv; + + tv.tv_sec = 0; + tv.tv_nsec = 200000000; + while (!end_thread) { + nanosleep(&tv, NULL); + /* trigger the extech to send data */ + ret = write(fd, " ", 1); + if (ret < 0) + continue; + + sum += extech_read(fd); + samples++; + + } +} + +extern "C" +{ + void* thread_proc(void *arg) + { + class extech_power_meter *parent; + parent = (class extech_power_meter*)arg; + parent->sample(); + return 0; + } +} + +void extech_power_meter::end_measurement(void) +{ + end_thread = 1; + pthread_join( thread, NULL); + if (samples){ + rate = sum / samples; + } + else + measure(); +} + +void extech_power_meter::start_measurement(void) +{ + end_thread = 0; + sum = samples = 0; + + if (pthread_create(&thread, NULL, thread_proc, this)) + fprintf(stderr, "ERROR: extech measurement thread creation failed\n"); + +} + + +double extech_power_meter::power(void) +{ + return rate; +} diff --git a/src/measurement/extech.h b/src/measurement/extech.h new file mode 100644 index 0000000..b7b330a --- /dev/null +++ b/src/measurement/extech.h @@ -0,0 +1,51 @@ +/* + * Copyright 2010, Intel Corporation + * + * 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: + * Arjan van de Ven <arjan@linux.intel.com> + */ +#ifndef __INCLUDE_GUARD_EXTECH_H +#define __INCLUDE_GUARD_EXTECH_H + +#include <pthread.h> +#include "measurement.h" + +class extech_power_meter: public power_meter { + char dev_name[256]; + int fd; + + double rate; + void measure(void); + double sum; + int samples; + int end_thread; + pthread_t thread; +public: + extech_power_meter(const char *_dev_name); + virtual void start_measurement(void); + virtual void end_measurement(void); + virtual void sample(void); + + virtual double power(void); + virtual double dev_capacity(void) { return 0.0; }; +}; + +#endif diff --git a/src/measurement/measurement.cpp b/src/measurement/measurement.cpp new file mode 100644 index 0000000..caee24e --- /dev/null +++ b/src/measurement/measurement.cpp @@ -0,0 +1,188 @@ +/* + * Copyright 2010, Intel Corporation + * + * 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: + * Arjan van de Ven <arjan@linux.intel.com> + */ +#include "measurement.h" +#include "acpi.h" +#include "extech.h" +#include "sysfs.h" +#include "opal-sensors.h" +#include "../parameters/parameters.h" +#include "../lib.h" + +#include <string> +#include <sys/types.h> +#include <dirent.h> +#include <stdio.h> +#include <fstream> +#include <unistd.h> +#include <time.h> + +double min_power = 50000.0; + +void power_meter::start_measurement(void) +{ +} + + +void power_meter::end_measurement(void) +{ +} + + +double power_meter::power(void) +{ + return 0.0; +} + +vector<class power_meter *> power_meters; + +static struct timespec tlast; + +void start_power_measurement(void) +{ + unsigned int i; + clock_gettime(CLOCK_REALTIME, &tlast); + for (i = 0; i < power_meters.size(); i++) + power_meters[i]->start_measurement(); + all_results.joules = 0.0; +} +void end_power_measurement(void) +{ + unsigned int i; + for (i = 0; i < power_meters.size(); i++) + power_meters[i]->end_measurement(); +} + +double global_power(void) +{ + bool global_discharging = false; + double total = 0.0; + unsigned int i; + + for (i = 0; i < power_meters.size(); i++) { + global_discharging |= power_meters[i]->is_discharging(); + total += power_meters[i]->power(); + } + + /* report global time left if at least one battery is discharging */ + if (!global_discharging) + return 0.0; + + all_results.power = total; + if (total < min_power && total > 0.01) + min_power = total; + return total; +} + +void global_sample_power(void) +{ + struct timespec tnow; + + clock_gettime(CLOCK_REALTIME, &tnow); + /* power * time = joules */ + all_results.joules += global_power() * \ + ( ((double)tnow.tv_sec + 1.0e-9*tnow.tv_nsec) - \ + ((double)tlast.tv_sec + 1.0e-9*tlast.tv_nsec)); + tlast = tnow; +} + +double global_joules(void) +{ + return all_results.joules; +} + +double global_time_left(void) +{ + bool global_discharging = false; + double total_capacity = 0.0; + double total_rate = 0.0; + unsigned int i; + for (i = 0; i < power_meters.size(); i++) { + global_discharging |= power_meters[i]->is_discharging(); + total_capacity += power_meters[i]->dev_capacity(); + total_rate += power_meters[i]->power(); + } + /* report global time left if at least one battery is discharging */ + if (!global_discharging) + return 0.0; + + /* return 0.0 instead of INF+ */ + if (total_rate < 0.001) + return 0.0; + return total_capacity / total_rate; +} + +void sysfs_power_meters_callback(const char *d_name) +{ + std::string type = read_sysfs_string("/sys/class/power_supply/%s/type", d_name); + + if (type != "Battery" && type != "UPS") + return; + + class sysfs_power_meter *meter; + meter = new(std::nothrow) class sysfs_power_meter(d_name); + if (meter) + power_meters.push_back(meter); +} + +void acpi_power_meters_callback(const char *d_name) +{ + class acpi_power_meter *meter; + meter = new(std::nothrow) class acpi_power_meter(d_name); + if (meter) + power_meters.push_back(meter); +} + +void sysfs_opal_sensors_callback(const char *d_name) +{ + class opal_sensors_power_meter *meter; + const char *c; + + /* Those that end in / are directories and we don't want them */ + c = strrchr(d_name, '/'); + if (c && *(c+1) == '\0') + return; + + meter = new(std::nothrow) class opal_sensors_power_meter(d_name); + if (meter) + power_meters.push_back(meter); +} + +void detect_power_meters(void) +{ + process_directory("/sys/class/power_supply", sysfs_power_meters_callback); + process_glob("/sys/devices/platform/opal-sensor/hwmon/hwmon*/power*", sysfs_opal_sensors_callback); + if (power_meters.size() == 0) { + process_directory("/proc/acpi/battery", acpi_power_meters_callback); + } +} + +void extech_power_meter(const char *devnode) +{ + class extech_power_meter *meter; + + meter = new class extech_power_meter(devnode); + + power_meters.push_back(meter); +} diff --git a/src/measurement/measurement.h b/src/measurement/measurement.h new file mode 100644 index 0000000..9a84bc2 --- /dev/null +++ b/src/measurement/measurement.h @@ -0,0 +1,71 @@ +/* + * Copyright 2010, Intel Corporation + * + * 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: + * Arjan van de Ven <arjan@linux.intel.com> + */ +#ifndef __INCLUDE_GUARD_MEASUREMENT_H +#define __INCLUDE_GUARD_MEASUREMENT_H + +#include <vector> + +using namespace std; + +class power_meter { + bool discharging = false; +public: + virtual ~power_meter() {}; + + virtual void start_measurement(void); + virtual void end_measurement(void); + virtual double power(void); + + virtual double dev_capacity(void) + { + return 0.0; /* in Joules */ + } + + virtual void set_discharging(bool d) + { + discharging = d; + } + + virtual bool is_discharging() + { + return discharging; + } +}; + +extern vector<class power_meter *> power_meters; + +extern void start_power_measurement(void); +extern void end_power_measurement(void); +extern double global_power(void); +extern void global_sample_power(void); +extern double global_joules(void); +extern double global_time_left(void); + +extern void detect_power_meters(void); +extern void extech_power_meter(const char *devnode); + +extern double min_power; + +#endif diff --git a/src/measurement/opal-sensors.cpp b/src/measurement/opal-sensors.cpp new file mode 100644 index 0000000..a70ec56 --- /dev/null +++ b/src/measurement/opal-sensors.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015 IBM Corp. + * + * 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: + * Stewart Smith <stewart@linux.vnet.ibm.com> + */ +#include "measurement.h" +#include "opal-sensors.h" +#include "../lib.h" +#include <string.h> +#include <stdio.h> +#include <limits.h> + +opal_sensors_power_meter::opal_sensors_power_meter(const char *power_supply_name) +{ + strncpy(name, power_supply_name, sizeof(name)); +} + +double opal_sensors_power_meter::power(void) +{ + bool ok; + int value; + double r = 0; + + value = read_sysfs(name, &ok); + + if(ok) + r = value / 1000000.0; + return r; +} diff --git a/src/measurement/opal-sensors.h b/src/measurement/opal-sensors.h new file mode 100644 index 0000000..7962091 --- /dev/null +++ b/src/measurement/opal-sensors.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015 IBM Corp. + * + * 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: + * Stewart Smith <stewart@linux.vnet.ibm.com> + */ +#ifndef INCLUDE_GUARD_OPAL_SENSORS_H +#define INCLUDE_GUARD_OPAL_SENSORS_H + +#include "measurement.h" +#include <limits.h> + +class opal_sensors_power_meter: public power_meter { + char name[PATH_MAX]; +public: + opal_sensors_power_meter(const char *power_supply_name); + virtual void start_measurement(void) {}; + virtual void end_measurement(void) {}; + + virtual double power(void); + virtual double dev_capacity(void) { return 0.0; } +}; + +#endif diff --git a/src/measurement/sysfs.cpp b/src/measurement/sysfs.cpp new file mode 100644 index 0000000..c5a7a12 --- /dev/null +++ b/src/measurement/sysfs.cpp @@ -0,0 +1,160 @@ +/* + * 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> +#include <limits.h> + +sysfs_power_meter::sysfs_power_meter(const char *power_supply_name) +{ + rate = 0.0; + capacity = 0.0; + pt_strcpy(name, power_supply_name); +} + +bool sysfs_power_meter::get_sysfs_attr(const char *attribute, int *value) +{ + char filename[PATH_MAX]; + 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", ¤t)) + 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; + this->set_discharging(false); + + if (!is_present()) + return; + /** do not jump over. we may have discharging battery */ + if (read_sysfs_string("/sys/class/power_supply/%s/status", name) == "Discharging") + this->set_discharging(true); + + 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 */ +} diff --git a/src/measurement/sysfs.h b/src/measurement/sysfs.h new file mode 100644 index 0000000..5b440f5 --- /dev/null +++ b/src/measurement/sysfs.h @@ -0,0 +1,55 @@ +/* + * 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> + */ +#ifndef INCLUDE_GUARD_SYSFS_H +#define INCLUDE_GUARD_SYSFS_H + +#include "measurement.h" + +class sysfs_power_meter: public power_meter { + char name[256]; + + double capacity; + double rate; + + bool get_sysfs_attr(const char *attribute, int *value); + bool is_present(); + double get_voltage(); + + bool set_rate_from_power(); + bool set_rate_from_current(double voltage); + bool set_capacity_from_energy(); + bool set_capacity_from_charge(double voltage); + + void measure(); +public: + sysfs_power_meter(const char *power_supply_name); + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double power(void) { return rate; } + virtual double dev_capacity(void) { return capacity; } +}; + +#endif |