aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArjan van de Ven <arjan@linux.intel.com>2011-04-27 17:58:27 -0400
committerArjan van de Ven <arjan@linux.intel.com>2011-04-27 17:58:27 -0400
commite0b2b5915ebbbea065efdf11c230b6b7b7874ae3 (patch)
tree46cbb0057259e1ddc8fbc8cd1b993a391bff8528
parent665ddc93684a05774079256d51be06996b5750c7 (diff)
downloadpowertop-e0b2b5915ebbbea065efdf11c230b6b7b7874ae3.tar.gz
add basic extech support
-rw-r--r--Makefile2
-rw-r--r--csstoh.c2
-rw-r--r--measurement/extech.cpp312
-rw-r--r--measurement/extech.h45
-rw-r--r--measurement/measurement.cpp10
5 files changed, 369 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 36cd870..da59e6f 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/csstoh.c b/csstoh.c
index 26567a6..e6b1dcf 100644
--- a/csstoh.c
+++ b/csstoh.c
@@ -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);
+
}