stumpwm-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[STUMP] [PATCH] Add battery2.lisp - works with multiple batteries, uses


From: John Li
Subject: [STUMP] [PATCH] Add battery2.lisp - works with multiple batteries, uses sysfs.
Date: Sun, 20 Jul 2008 08:11:43 -0400
User-agent: Mutt/1.5.18 (2008-05-17)

---
I rewrote battery.lisp. Mine:
- uses sysfs and works with 2.6.25 kernels (which have no
  /proc/apci/battery/ (which I noticed when my stump started crashing
  hard on reboot))
- works multiple batteries (or at least should! I have none to test)
- is designed to be easy to write your own formatter, if you don't
  like my tastes.
- is (should be) very crash-resistant
- is cleaner :) (to me)

Notes:
- The formatter uses UTF characters ↑ and ↓ (U+2191 and U+2193) to
  indicate charging and discharging. Do most people use a stumpwm font
  with these characters? I think they look very nice.
- The formatter relies on my bar-zone-color patch from a few days ago;
  I've added some commented code you can use if you don't have that
  patch.
- The defun-cached macro would be useful for all formatters that you
  wouldn't want to call every time you switch a frame or otherwise
  cause the mode-line to update. It'd fit perfectly with cpu.lisp, for
  one.

I'd really appreciate testing, particularly from people with multiple
batteries. I don't know Shawn's policy on contrib/ module code
quality, but I took care not to stomp on battery.lisp, so they could
co-exist... :)

 contrib/battery2.lisp |  142 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 142 insertions(+), 0 deletions(-)
 create mode 100644 contrib/battery2.lisp

diff --git a/contrib/battery2.lisp b/contrib/battery2.lisp
new file mode 100644
index 0000000..bcd1936
--- /dev/null
+++ b/contrib/battery2.lisp
@@ -0,0 +1,142 @@
+;;; Battery information formatters for the mode-line
+;;;
+;;; Copyright 2008 John Li
+;;;
+;;; Maintainer: John Li
+;;;
+;;; This module 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; either version 2, or (at your option)
+;;; any later version.
+;;;
+;;; This module 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 software; see the file COPYING.  If not, write to
+;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+;;; Boston, MA 02111-1307 USA
+;;;
+
+;;; USAGE:
+;;;
+;;; Place the following line in your ~/.stumpwmrc
+;;;
+;;;     (load "/path/to/battery2.lisp")
+;;;
+;;; Then use "%B" in your mode-line format.
+;;;
+;;; NOTES:
+;;;
+;;; This is specific to Linux and accesses information through
+;;; sysfs. The files used may vary depending on your kernel version
+;;; and it would not be surprising for them to continue to change in
+;;; the future.
+;;;
+;;; This is designed to be easy to customize, since you might prefer a
+;;; different display. Simply define your own fmt-bat function after
+;;; loading this file in your .stumpwmrc; bat-perc and bat-time are
+;;; functions that you can use.
+
+(pushnew '(#\B fmt-bat) *screen-mode-line-formatters* :test 'equal)
+
+(defvar *bat-wait-time* 5
+  "Don't update the battery information more often than once every 10
+seconds.")
+
+(defmacro defun-cached (name interval arglist &body body)
+  "Creates a function that does simple caching. The body must be
+written in a functional style - the value returned is set as the
+prev-val."
+  (let ((prev-time (gensym "prev-time"))
+        (prev-val (gensym "prev-val"))
+        (now (gensym "now"))
+        (docstring (when (stringp (car body))
+                     (pop body)))
+        (declares (loop while (and (listp (car body))
+                                   (eq 'declare (caar body)))
+                     collect (pop body))))
+      `(progn (defvar ,prev-time 0)
+              (defvar ,prev-val nil)
+              (defun ,name ,arglist
+                ;; if no docstring, return nothing (not even nil)
+                ,@(when docstring (list docstring))
+                ,@declares
+                (let ((,now (/ (get-internal-real-time)
+                               internal-time-units-per-second)))
+                  (when (>= (- ,now ,prev-time) ,interval)
+                    (setf ,prev-time ,now)
+                    (setf ,prev-val (progn ,@body)))
+                  ,prev-val)))))
+
+(defun bat-data (bat data)
+  "Gets the data for the corresponding file under the given battery's
+sysfs path. If the data is an integer, the integer is returned. If the
+file doesn't exist, nil is returned."
+  (with-open-file (s (merge-pathnames bat data)
+                     :direction :input :if-does-not-exist nil)
+    (when s
+      (let* ((val (read-line s nil))
+             (int (ignore-errors (parse-integer val))))
+        (if int
+            int
+            val)))))
+
+(defun parse-time (float-hour)
+  "Takes a floating point hour and returns a string of the form hh:mm."
+  (multiple-value-bind (h m) (truncate (* 60 float-hour) 60)
+    (format nil "~D:~2,'0D" h (round m))))
+
+(defun bat-time (status charge current &optional (full t))
+  "Returns either how much battery time is left when discharging or
+how much time remains until fully charged. If any required info is
+missing, returns nil."
+  (when (and status charge current full)
+    (cond ((string= status "Full") "")
+          ;; when switching from "Full" to "Discharging" status,
+          ;; there's a chance that current is 0
+          ((string= status "Discharging")
+           (ignore-errors (parse-time (/ charge current))))
+          ((string= status "Charging")
+           (ignore-errors (parse-time (/ (- full charge) current))))
+          (t "?"))))
+
+(defun bat-perc (charge full)
+  (when (and charge full)
+    (round (* 100 (/ charge full)))))
+
+(defun bat-status (bat)
+  "Prints information about the given battery. Example output:
+3:50- 90%   battery at 90%, discharging, and you have 3:50 left
+0:50+ 74%   battery at 74%, charging, ~50 minutes until fully charged
+~ 100%      battery is full"
+  (let* ((status (bat-data bat "status"))
+         (charge (bat-data bat "charge_now"))
+         (full (bat-data bat "charge_full"))
+         (current (bat-data bat "current_now"))
+         (time (bat-time status charge current full))
+         (status-icon (cond ((string= status "Full") "~")
+                            ((string= status "Discharging") "↓")
+                            ((string= status "Charging") "↑")
+                            (t "?")))
+         (perc (bat-perc charge full)))
+; if you don't have my bar-zone-color patch (mailed on 20080718), use this:
+;    (format nil "~A~A ~A%"
+;            time status-icon perc)))
+    (format nil "~A~A ^[~A~A%^]"
+            time status-icon (bar-zone-color perc 50 30 20 t) perc)))
+
+(defun-cached fmt-bat *bat-wait-time* (ml)
+  "Prints the battery status of all batteries in *bat-list* not more
+often that *bat-wait-time* seconds using the defun-cached macro."
+  (declare (ignore ml))
+  (let ((bat-list (directory #P"/sys/class/power_supply/BAT*/")))
+    (cond ((null bat-list) "nil")
+          ((cadr bat-list) (let ((acc nil))
+                             (dolist (b bat-list)
+                               (push b acc)
+                               (push (bat-status b) acc))
+                             (format nil "~{~A: ~A~^ |~}" (nreverse acc))))
+          (t (bat-status (car bat-list))))))
-- 
1.5.6





reply via email to

[Prev in Thread] Current Thread [Next in Thread]