LED Monitor 3.0 already.
1.0: C + Python w/ fork
2.0: Pure C w/ fork
3.0: Pure C w/o fork
Again, patch an empty directory with this email.
patch -p1 < /path/to/email/file
========================================
diff -Naur sg2vhe/Makefile C2/Makefile
--- sg2vhe/Makefile 1969-12-31 18:00:00.000000000 -0600
+++ C2/Makefile 2006-03-25 01:52:59.000000000 -0600
@@ -0,0 +1,8 @@
+CFLAGS=-march=pentium-mmx -Os
+
+battmon: main.c acpi.c
+ $(CC) $(CFLAGS) -o battmon main.c acpi.c
+ strip battmon
+
+acpi.c: acpi.h
+ touch acpi.c
diff -Naur sg2vhe/acpi.c C2/acpi.c
--- sg2vhe/acpi.c 1969-12-31 18:00:00.000000000 -0600
+++ C2/acpi.c 2006-03-25 03:18:41.000000000 -0600
@@ -0,0 +1,242 @@
+/*
+ * A not-yet-general-purpose ACPI library, by Joey Hess <joey@kitenet.net>
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "acpi.h"
+
+#define PROC_ACPI "/proc/acpi"
+#define ACPI_MAXITEM 8
+
+int acpi_batt_count = 0;
+/* Filenames of the battery info files for each system battery. */
+char acpi_batt_info[ACPI_MAXITEM][128];
+/* Filenames of the battery status files for each system battery. */
+char acpi_batt_status[ACPI_MAXITEM][128];
+/* Stores battery capacity, or 0 if the battery is absent. */
+int acpi_batt_capacity[ACPI_MAXITEM];
+
+int acpi_ac_count = 0;
+char acpi_ac_adapter_info[ACPI_MAXITEM][128];
+char acpi_ac_adapter_status[ACPI_MAXITEM][128];
+
+/* These are the strings used in the ACPI shipped with the 2.4 kernels */
+char *acpi_labels_old[] = {
+ "info",
+ "status",
+ "/proc/acpi/battery",
+ "/proc/acpi/ac_adapter",
+ "on-line",
+ "Design Capacity:",
+ "Present:",
+ "Remaining Capacity:",
+ "Present Rate:",
+ "State:",
+ "Status:",
+ NULL
+};
+
+/* These are the strings used in ACPI in the 2.5 kernels, circa version
+ * 20020214 */
+char *acpi_labels_20020214[] = {
+ "info",
+ "state",
+ "/proc/acpi/battery",
+ "/proc/acpi/ac_adapter",
+ "on-line",
+ "design capacity:",
+ "present:",
+ "remaining capacity:",
+ "present rate:",
+ "charging state:",
+ "state:",
+ NULL
+};
+
+char **acpi_labels = NULL;
+
+/* Read in an entire ACPI proc file (well, the first 1024 bytes anyway), and
+ * return a statically allocated array containing it. */
+inline char *get_acpi_file (const char *file) {
+ int fd;
+ int end;
+ static char buf[1024];
+ fd = open(file, O_RDONLY);
+ if (fd == -1) return NULL;
+ end = read(fd, buf, sizeof(buf));
+ buf[end] = '\0';
+ close(fd);
+ return buf;
+}
+
+/* Given a buffer holding an acpi file, searches for the given key in it,
+ * and returns the numeric value. 0 is returned on failure. */
+inline int scan_acpi_num (const char *buf, const char *key) {
+ char *ptr;
+ int ret;
+ if ((ptr = strstr(buf, key))) {
+ if (sscanf(ptr + strlen(key), "%d", &ret) == 1)
+ return ret;
+ }
+ return 0;
+}
+
+/* Given a buffer holding an acpi file, searches for the given key in it,
+ * and returns its value in a statically allocated string. */
+inline char *scan_acpi_value (const char *buf, const char *key) {
+ char *ptr;
+ static char ret[256];
+
+ if ((ptr = strstr(buf, key))) {
+ if (sscanf(ptr + strlen(key), "%s", ret) == 1)
+ return ret;
+ }
+ return NULL;
+}
+
+/* Read an ACPI proc file, pull out the requested piece of information, and
+ * return it (statically allocated string). Returns NULL on error, This is
+ * the slow, dumb way, fine for initialization or if only one value is needed
+ * from a file, slow if called many times. */
+char *get_acpi_value (const char *file, const char *key) {
+ char *buf = get_acpi_file(file);
+ if (! buf) return NULL;
+ return scan_acpi_value(buf, key);
+}
+
+/* Returns the design capacity of a battery. */
+int get_acpi_batt_capacity(int battery) {
+ int cap;
+ char *caps=get_acpi_value(acpi_batt_info[battery],
acpi_labels[label_design_capacity]);
+ if (caps == NULL)
+ cap=0; /* battery not present */
+ else
+ cap=atoi(caps);
+ /* This is ACPI's broken way of saying that there is no battery. */
+ if (cap == 655350)
+ return 0;
+ return cap;
+}
+
+/* Comparison function for qsort. */
+int _acpi_compare_strings (const void *a, const void *b) {
+ const char **pa = (const char **)a;
+ const char **pb = (const char **)b;
+ return strcasecmp((const char *)*pa, (const char *)*pb);
+}
+
+/* Find something (batteries, ac adpaters, etc), and set up a string array
+ * to hold the paths to info and status files of the things found. Must be
+ * in /proc/acpi to call this. Returns the number of items found. */
+int find_items (char *itemname, char infoarray[ACPI_MAXITEM][128],
+ char statusarray[ACPI_MAXITEM][128]) {
+ DIR *dir;
+ struct dirent *ent;
+ int num_devices=0;
+ int i;
+ char **devices = malloc(ACPI_MAXITEM * sizeof(char *));
+
+ dir = opendir(itemname);
+ if (dir == NULL)
+ return 0;
+ while ((ent = readdir(dir))) {
+ if (!strncmp(".", ent->d_name, 1) ||
+ !strncmp("..", ent->d_name, 2))
+ continue;
+
+ devices[num_devices]=strdup(ent->d_name);
+ num_devices++;
+ if (num_devices >= ACPI_MAXITEM)
+ break;
+ }
+ closedir(dir);
+
+ /* Sort, since readdir can return in any order. /proc/does
+ * sometimes list BATT2 before BATT1. */
+ qsort(devices, num_devices, sizeof(char *), _acpi_compare_strings);
+
+ for (i = 0; i < num_devices; i++) {
+ sprintf(infoarray[i], "%s/%s/%s", itemname, devices[i],
+ acpi_labels[label_info]);
+ sprintf(statusarray[i], "%s/%s/%s", itemname, devices[i],
+ acpi_labels[label_status]);
+ free(devices[i]);
+ }
+
+ return num_devices;
+}
+
+/* Find batteries, return the number, and set acpi_batt_count to it as well. */
+int find_batteries(void) {
+ int i;
+ acpi_batt_count = find_items(acpi_labels[label_battery],
acpi_batt_info, acpi_batt_status);
+ /* Read in the last charged capacity of the batteries. */
+ for (i = 0; i < acpi_batt_count; i++)
+ acpi_batt_capacity[i] = get_acpi_batt_capacity(i);
+ return acpi_batt_count;
+}
+
+/* Find AC power adapters, return the number found, and set acpi_ac_count to it
+ * as well. */
+int find_ac_adapters(void) {
+ acpi_ac_count = find_items(acpi_labels[label_ac_adapter],
acpi_ac_adapter_info, acpi_ac_adapter_status);
+ return acpi_ac_count;
+}
+
+/* Returns true if the system is on ac power. Call find_ac_adapters first. */
+int on_ac_power (void) {
+ int i;
+ for (i = 0; i < acpi_ac_count; i++) {
+ if (strcmp(acpi_labels[label_online],
get_acpi_value(acpi_ac_adapter_status[i],
acpi_labels[label_ac_state])) == 0)
+ return 1;
+ else
+ return 0;
+ }
+ return 0;
+}
+
+/* See if we have ACPI support and check version. Also find batteries and
+ * ac power adapters. */
+int acpi_supported (void) {
+ char *version;
+ int num;
+
+ if (chdir(PROC_ACPI) == -1) {
+ return 0;
+ }
+
+ version = get_acpi_value("/proc/acpi/info", "ACPI-CA Version:");
+ if (version == NULL) {
+ /* 2.5 kernel acpi */
+ version = get_acpi_value("/proc/acpi/info", "version:");
+ }
+ if (version == NULL) {
+ return 0;
+ }
+ num = atoi(version);
+ if (num < ACPI_VERSION) {
+ fprintf(stderr, "ACPI subsystem %s too is old, consider upgrading to %i.\n",
+ version, ACPI_VERSION);
+ return 0;
+ }
+ else if (num >= 20020214) {
+ acpi_labels = acpi_labels_20020214;
+ }
+ else {
+ acpi_labels = acpi_labels_old;
+ }
+
+ find_batteries();
+ find_ac_adapters();
+
+ return 1;
+}
diff -Naur sg2vhe/acpi.h C2/acpi.h
--- sg2vhe/acpi.h 1969-12-31 18:00:00.000000000 -0600
+++ C2/acpi.h 2006-03-25 03:17:51.000000000 -0600
@@ -0,0 +1,54 @@
+/*
+ * A not-yet-general-purpose ACPI library, by Joey Hess <joey@kitenet.net>
+ */
+
+/* Define ACPI_THERMAL to make the library support finding info about thermal
+ * sources. */
+//#define ACPI_THERMAL 1
+
+/* Define ACPI_APM to get the acpi_read function, which is like apm_read. */
+//#define ACPI_APM 1
+
+/* The lowest version of ACPI proc files supported. */
+#define ACPI_VERSION 20011018
+
+/* The number of acpi items of each class supported. */
+#define ACPI_MAXITEM 8
+
+int acpi_supported (void);
+char *get_acpi_file (const char *file);
+int scan_acpi_num (const char *buf, const char *key);
+char *scan_acpi_value (const char *buf, const char *key);
+char *get_acpi_value (const char *file, const char *key);
+int get_acpi_batt_capacity(int battery);
+
+extern int acpi_batt_count;
+/* Filenames of the battery info files for each system battery. */
+extern char acpi_batt_info[ACPI_MAXITEM][128];
+/* Filenames of the battery status files for each system battery. */
+extern char acpi_batt_status[ACPI_MAXITEM][128];
+/* Stores battery capacity, or 0 if the battery is absent. */
+extern int acpi_batt_capacity[ACPI_MAXITEM];
+
+extern int acpi_ac_count;
+extern char acpi_ac_adapter_info[ACPI_MAXITEM][128];
+extern char acpi_ac_adapter_status[ACPI_MAXITEM][128];
+
+/* This enum is used to index into the acpi_labels */
+enum acpi_labels_items {
+ label_info,
+ label_status,
+ label_battery,
+ label_ac_adapter,
+ label_online,
+ label_design_capacity,
+ label_present,
+ label_remaining_capacity,
+ label_present_rate,
+ label_charging_state,
+ label_ac_state,
+};
+
+/* This is set to point to a list of strings used for the given acpi
+ * * version. */
+extern char **acpi_labels;
diff -Naur sg2vhe/main.c C2/main.c
--- sg2vhe/main.c 1969-12-31 18:00:00.000000000 -0600
+++ C2/main.c 2006-03-25 03:06:59.000000000 -0600
@@ -0,0 +1,118 @@
+#include <signal.h>
+#include "acpi.h"
+#include <fcntl.h>
+
+typedef enum {
+ state_discharging,
+ state_charged,
+ state_charging
+} state_t;
+
+float charge;
+state_t state;
+int quit;
+
+state_t getBatteryState(int battery)
+{
+ char *strstate;
+ strstate = get_acpi_value(acpi_batt_status[battery],
"charging state:");
+
+ if(!strncmp("discharging", strstate, 11))
+ return state_discharging;
+ if(!strncmp("charged", strstate, 7))
+ return state_charged;
+ if(!strncmp("charging", strstate, 8))
+ return state_charging;
+}
+
+void sighandler (int signal)
+{
+ static state_t lstate;
+ static int maxcap, curcap, i;
+
+ switch(signal)
+ {
+ case SIGTERM:
+ case SIGINT:
+ quit = 1;
+ break;
+ case SIGALRM:
+ alarm(2);
+ maxcap = curcap = state = 0;
+ for(i = 0; i < acpi_batt_count; i++)
+ {
+ maxcap += scan_acpi_num(get_acpi_file(acpi_batt_info[i]), "last
full capacity:");
+ curcap += curcap +=
scan_acpi_num(get_acpi_file(acpi_batt_status[i]), "remaining
capacity:");
+ lstate = getBatteryState(i);
+ state = (state > lstate) ? state : lstate;
+ }
+ charge = 100.0*((float)curcap/(float)maxcap);
+ }
+}
+
+int main()
+{
+ int ledfile = open("/proc/acpi/ibm/led", O_WRONLY);
+ int i, duty;
+
+ quit = 0;
+
+ if(!acpi_supported())
+ return 1;
+
+ find_batteries();
+
+ signal(SIGINT, sighandler);
+ signal(SIGTERM, sighandler);
+ signal(SIGALRM, sighandler);
+
+ sighandler(SIGALRM);
+
+ while(!quit)
+ {
+
+ switch(state)
+ {
+ case state_discharging:
+ if(charge < 5.0)
+ {
+ duty = (int)(charge * 100000);
+ write(ledfile, "1on,2off\n", 9);
+ usleep(duty);
+ write(ledfile, "1off\n", 5);
+ usleep(duty);
+ }
+ else
+ {
+ duty = (int)((charge - 5.0)*300 / .95);
+ for(i = 0; i < 30; i++)
+ {
+ write(ledfile, "2on,1off\n", 9);
+ usleep(duty);
+ write(ledfile, "1on,2off\n", 9);
+ usleep(30000-duty);
+ }
+ }
+ break;
+ case state_charged:
+ write(ledfile, "2on,1off\n", 9);
+ usleep(750000);
+ write(ledfile, "2off\n", 5);
+ usleep(250000);
+ break;
+ case state_charging:
+ duty = (int)(charge * 300);
+ for(i = duty; i < 30000; i+=300)
+ {
+ write(ledfile, "2on,1off\n", 9);
+ usleep(i);
+ write(ledfile, "1on,2off\n", 9);
+ usleep(30000-i);
+ }
+ break;
+ }
+ }
+
+ close(ledfile);
+ return 0;
+}
_______________________________________________
Thinkpad mailing list
Thinkpad@stderr.org
http://stderr.org/cgi-bin/mailman/listinfo/thinkpad
Received on Sat Mar 25 03:16:56 2006
This archive was generated by hypermail 2.1.8 : Tue May 30 2006 - 16:00:08 EDT