diff options
author | Arjan van de Ven <arjan@linux.intel.com> | 2011-04-27 17:58:27 -0400 |
---|---|---|
committer | Arjan van de Ven <arjan@linux.intel.com> | 2011-04-27 17:58:27 -0400 |
commit | e0b2b5915ebbbea065efdf11c230b6b7b7874ae3 (patch) | |
tree | 46cbb0057259e1ddc8fbc8cd1b993a391bff8528 | |
parent | 665ddc93684a05774079256d51be06996b5750c7 (diff) | |
download | powertop-e0b2b5915ebbbea065efdf11c230b6b7b7874ae3.tar.gz |
add basic extech support
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | csstoh.c | 2 | ||||
-rw-r--r-- | measurement/extech.cpp | 312 | ||||
-rw-r--r-- | measurement/extech.h | 45 | ||||
-rw-r--r-- | measurement/measurement.cpp | 10 |
5 files changed, 369 insertions, 2 deletions
@@ -13,7 +13,7 @@ OBJS += perf/perf.o perf/perf_bundle.o OBJS += process/process.o process/do_process.o process/interrupt.o process/timer.o process/work.o process/powerconsumer.o process/device.o DEVS += devices/device.o devices/backlight.o devices/usb.o devices/ahci.o devices/alsa.o devices/rfkill.o devices/i915-gpu.o devices/thinkpad-fan.o devices/network.o devices/thinkpad-light.o DEVS += devices/runtime_pm.o -DEVS += measurement/measurement.o measurement/acpi.o +DEVS += measurement/measurement.o measurement/acpi.o measurement/extech.o OBJS += $(DEVS) OBJS += parameters/parameters.o parameters/learn.o parameters/persistent.o OBJS += calibrate/calibrate.o @@ -65,5 +65,5 @@ int main(int argc, char **argv) fprintf(out, "#endif\n"); fclose(out); fclose(in); - return(0); + return EXIT_SUCCESS; } diff --git a/measurement/extech.cpp b/measurement/extech.cpp new file mode 100644 index 0000000..23a326f --- /dev/null +++ b/measurement/extech.cpp @@ -0,0 +1,312 @@ +/* + * 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 <iostream> +#include <fstream> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +using namespace std; + +static const char * device = "/dev/ttyUSB0"; + + +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; + + 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; + strncpy(dev_name, extech_name, sizeof(dev_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) +{ + int ret; + /* trigger the extech to send data */ + ret = write(fd, " ", 1); + + rate = extech_read(fd); + +} + + +void extech_power_meter::end_measurement(void) +{ + measure(); +} + +void extech_power_meter::start_measurement(void) +{ + /* ACPI battery state is a lagging indication, lets only measure at the end */ +} + + +double extech_power_meter::joules_consumed(void) +{ + return rate; +} diff --git a/measurement/extech.h b/measurement/extech.h new file mode 100644 index 0000000..98f854b --- /dev/null +++ b/measurement/extech.h @@ -0,0 +1,45 @@ +/* + * 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 "measurement.h" + +class extech_power_meter: public power_meter { + char dev_name[256]; + int fd; + + double rate; + void measure(void); +public: + extech_power_meter(const char *_dev_name); + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double joules_consumed(void); + virtual double dev_capacity(void) { return 0.0; }; +}; + +#endif diff --git a/measurement/measurement.cpp b/measurement/measurement.cpp index 9db4a12..9953183 100644 --- a/measurement/measurement.cpp +++ b/measurement/measurement.cpp @@ -24,6 +24,7 @@ */ #include "measurement.h" #include "acpi.h" +#include "extech.h" #include "../parameters/parameters.h" #include "../lib.h" @@ -107,6 +108,14 @@ void detect_power_meters(void) { DIR *dir; struct dirent *entry; + + if (0) { + class extech_power_meter *meter; + + meter = new class extech_power_meter("/dev/ttyUSB0"); + + power_meters.push_back(meter); + } dir = opendir("/proc/acpi/battery"); if (!dir) @@ -125,4 +134,5 @@ void detect_power_meters(void) } closedir(dir); + } |