Re: [PATCH] Linux ACPI support for battery applet
Michal Ludvig <[email protected]> Thu, 15 Sep 2005 15:28:24 +1200
| Newsgroups | gmane.comp.handhelds.matchbox |
|---|---|
| Message-ID | <[email protected]> |
This is an OpenPGP/MIME signed message (RFC 2440 and 3156)
--===============0585047510==
Content-Type: multipart/signed; micalg=pgp-sha1;
protocol="application/pgp-signature";
boundary="------------enig269E4FA03322D51BD36A1C31"
This is an OpenPGP/MIME signed message (RFC 2440 and 3156)
--------------enig269E4FA03322D51BD36A1C31
Content-Type: multipart/mixed; boundary="------------050507080806040604020800"
This is a multi-part message in MIME format.
--------------050507080806040604020800
Content-Type: text/plain; charset=ISO-8859-2
Content-Transfer-Encoding: 7bit
Michal Ludvig wrote:
> Hi again,
>
> just in case anyone is interested, attached is a patch for
> mb-applet-battery that gathers the battery stats from /proc/acpi instead
> of from libapm. On our system we don't have APM at all and ACPI works
> just fine. Well, except for a short transition period after unplugging
> the AC powercord, where it gives out obviously wrong data. There are
> some simple checks to ignore these obviously too high or too low values.
Err, once again, now with the patch attached ;-)
Michal Ludvig
--
* Personal homepage: http://www.logix.cz/michal
--------------050507080806040604020800
Content-Type: text/plain;
name="battery-acpi.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="battery-acpi.diff"
Index: matchbox-panel/configure.ac
===================================================================
--- matchbox-panel/configure.ac (revision 1200)
+++ matchbox-panel/configure.ac (working copy)
@@ -4,7 +4,7 @@
AM_INIT_AUTOMAKE()
AM_MAINTAINER_MODE
-AM_CONFIG_HEADER([config.h])
+AM_CONFIG_HEADER(config.h)
# Checks for programs.
AC_GNU_SOURCE
@@ -52,6 +52,9 @@
[ --enable-debug enable debug ( verbose ) build],
enable_debug=$enableval, enable_debug=no )
+AC_ARG_ENABLE(acpi-linux,
+ [ --enable-acpi-linux obtain battery status from /proc/acpi on Linux],
+ enable_acpi_linux=$enableval, enable_acpi_linux=no )
PKG_CHECK_MODULES(LIBMB, libmb >= 1.6,,
AC_MSG_ERROR([*** Required Matchbox Library (libmb) 1.6 not installed ***]))
@@ -79,6 +82,12 @@
AC_DEFINE(USE_LIBSN, [1], [Has StartupNotification Support])
fi
+dnl ----- Linux ACPI -------------------------------------------------------
+
+if test x$enable_acpi_linux = xyes; then
+ AC_DEFINE(USE_ACPI_LINUX, [1], [Use /proc/acpi to get battery status])
+fi
+
dnl ----- NLS Fun -----------------------------------------------------------
INTLIBS=""
Index: matchbox-panel/applets/mb-applet-battery.c
===================================================================
--- matchbox-panel/applets/mb-applet-battery.c (revision 1200)
+++ matchbox-panel/applets/mb-applet-battery.c (working copy)
@@ -134,7 +134,173 @@
#endif
+#ifdef USE_ACPI_LINUX
+#define ACPI_PREFIX "/proc/acpi"
+#define BAT_PREFIX "battery/BAT0"
+#define AC_PREFIX "ac_adapter/AC0"
+
+/* ACPI sometimes reports incorrect values, especially
+ * shortly after unplugging the AC power. Tweak this for
+ * your hardware.
+ * See /proc/acpi/battery/BAT0/state:"present rate" for
+ * "normal" values on your system. */
+#define ACPI_RATE_MIN 300
+#define ACPI_RATE_MAX 5000
+
+struct avg_consumption {
+ unsigned long avg_values[100];
+ int avg_index;
+ int avg_records;
+ int countdown;
+};
+
+static struct avg_consumption a;
+
+static int
+read_apm(int *values)
+{
+ enum ac_state { AC_UNKNOWN = -1, AC_OFFLINE = 0, AC_ONLINE = 1 };
+ enum bat_state { BAT_UNKNOWN = -1, BAT_CHARGING = 1, BAT_DISCHARGING = 2 };
+
+ struct entry {
+ char *key;
+ char *value;
+ char *unit;
+ };
+
+ struct acpi_status {
+ enum ac_state ac_state;
+ enum bat_state bat_state;
+ unsigned long design_capacity;
+ unsigned long remaining_capacity;
+ unsigned long present_rate;
+ };
+
+ static int
+ line_parse(char *line, struct entry *e)
+ {
+ char *ptr;
+
+ ptr = strchr(line, ':');
+ if (!ptr)
+ return -1;
+ e->key = line;
+ *ptr = 0;
+ while (*++ptr && *ptr == ' ');
+ e->value = ptr;
+ while (*++ptr && *ptr != '\n' && *ptr != ' ');
+ *ptr = 0;
+ if (*++ptr) {
+ e->unit = ptr;
+ while (*++ptr && *ptr != '\n');
+ *ptr = 0;
+ } else
+ e->unit = 0;
+
+ return 0;
+ }
+
+ FILE *f;
+ char line[1024];
+ struct entry e;
+ struct acpi_status s;
+
+ memset (&s, 0, sizeof(s));
+
+ f = fopen(ACPI_PREFIX "/" AC_PREFIX "/state", "r");
+ if (f) {
+ while (fgets(line, sizeof(line), f)) {
+ if (line_parse(line, &e) < 0)
+ continue;
+ if (strcmp(e.key, "state") == 0) {
+ if(strcmp(e.value, "on-line") == 0)
+ s.ac_state = AC_ONLINE;
+ else if (strcmp(e.value, "off-line") == 0)
+ s.ac_state = AC_OFFLINE;
+ else
+ s.ac_state = AC_UNKNOWN;
+ }
+ }
+ fclose(f);
+ }
+
+ f = fopen(ACPI_PREFIX "/" BAT_PREFIX "/info", "r");
+ if (f) {
+ while (fgets(line, sizeof(line), f)) {
+ if (line_parse(line, &e) < 0)
+ continue;
+ if (strcmp(e.key, "design capacity") == 0)
+ sscanf(e.value, "%lu", &s.design_capacity);
+ }
+ fclose(f);
+ }
+
+ f = fopen(ACPI_PREFIX "/" BAT_PREFIX "/state", "r");
+ if (f) {
+ while (fgets(line, sizeof(line), f)) {
+ if (line_parse(line, &e) < 0)
+ continue;
+ if (strcmp(e.key, "remaining capacity") == 0)
+ sscanf(e.value, "%lu", &s.remaining_capacity);
+ else if (strcmp(e.key, "charging state") == 0) {
+ if (strcmp(e.value, "charging") == 0)
+ s.bat_state = BAT_CHARGING;
+ else if (strcmp(e.value, "discharging") == 0)
+ s.bat_state = BAT_DISCHARGING;
+ else
+ s.bat_state = BAT_UNKNOWN;
+ } else if (strcmp(e.key, "present rate") == 0)
+ sscanf(e.value, "%lu", &s.present_rate);
+ }
+ fclose(f);
+ }
+
+ /* Don't estimate TIME_LEFT on current power consumption. Instead
+ * compute some average and ignore too low/high values. */
+ values[TIME_LEFT] = 0;
+ if (s.bat_state != BAT_DISCHARGING && !a.countdown) {
+ memset(&a, 0, sizeof(a));
+ a.countdown = 10;
+ }
+ else if (s.bat_state == BAT_DISCHARGING && s.present_rate) {
+ int num_values = sizeof(a.avg_values)/sizeof(a.avg_values[0]);
+ unsigned long sum = 0;
+ int i;
+
+ if (a.countdown) {
+ a.countdown--;
+ goto bail_out;
+ }
+
+ if (s.present_rate < ACPI_RATE_MIN || s.present_rate > ACPI_RATE_MAX) {
+ goto bail_out;
+ }
+
+ a.avg_values[a.avg_index++] = s.present_rate;
+ a.avg_index %= num_values;
+ if (a.avg_records < num_values)
+ a.avg_records++;
+ if (a.avg_records > 10) {
+ for (i=0; i<a.avg_records; i++)
+ sum += a.avg_values[i];
+ values[TIME_LEFT] = s.remaining_capacity*60/(sum/a.avg_records);
+ }
+bail_out:
+ sum = 0; /* shut up gcc */
+ }
+
+ values[PERCENTAGE] = s.design_capacity ? s.remaining_capacity*100/s.design_capacity : 0;
+ values[AC_POWER] = s.ac_state;
+
+#if 0
+ printf("AC status: %d\n", values[AC_POWER]);
+ printf("Level: %d%%\n", values[PERCENTAGE]);
+ printf("Remaining: %d sec\n", values[TIME_LEFT]);
+#endif
+ return 1;
+}
+#else
#ifdef HAVE_APM_H
static int
@@ -180,6 +346,7 @@
}
#endif
+#endif /* Use ACPI */
void
fork_exec(char *cmd)
--------------050507080806040604020800--
--------------enig269E4FA03322D51BD36A1C31
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFDKOpYDDolCcRbIhgRArptAJ0cp0JJi/ro8kudbgllR7F0eVNj/ACgggn5
7cKK4Y8KNg1BIxpgluWI7a8=
=fWeT
-----END PGP SIGNATURE-----
--------------enig269E4FA03322D51BD36A1C31--
--===============0585047510==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
Matchbox mailing list
[email protected]
https://handhelds.org/mailman/listinfo/matchbox
--===============0585047510==--