[ltp] Speaking of battery charging....

Steve Thompson linux-thinkpad@linux-thinkpad.org
Tue, 27 Mar 2007 20:24:20 -0400 (EDT)


--0-595272767-1175041460=:1263
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 8bit
Content-Id: 
Content-Disposition: inline

I have this tiny little utility that shows battery state and temperature
information in the hardstatus line if you use screen(1).  I spen most of
my time looking (or often glaring) at an xterm or console session and like
to keep an eye on what's going on.  Screen, besides being generally
indespensible for serious shell work, will run periodically run a program
whose output is displayed in your terminal's hardstatus line.

Tested only with screen 4.0.2.


Regards,

Steve

__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 
--0-595272767-1175041460=:1263
Content-Type: text/x-csrc; name="screen_status_line.c"
Content-Description: 3291453960-screen_status_line.c
Content-Disposition: inline; filename="screen_status_line.c"

/*
    screen_status_line.c

    
    Extract information from /proc and/or /sys and format
    one line of output for `screen` to use in the hardware
    status line.


    (c) 2007, Steve Thompson <steve49152@yahoo.ca>

    version 0.001

    You may copy and use this software free of charge.  If you redistribute it, either with
    or without modifications, you must retain this copyright notice.  Neither I nor anyone
    else will assume any liabilty from your use of or inability to use this software.  

    "If it breaks, you get to keep both pieces."
	    -- Author unknown


    Instructons:

	1) Compile with gcc under Linux.
	2) Install the executable somewhere in your path.
	3) Edit your .screenrc and include something like the
	    following two entries, but modified for your setup:

	    backtick 1 30 1 /home/you/bin/screen_status_line
	    hardstatus lastline '%{= BW}%0c    %1`%=%{-}'            

	4) Read any relevant documentation you might need in order to
	    understand what this program does, how to install it, and
	    how it is intended to be used.

    
*/

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/mman.h>
#include <sys/stat.h>


/*
    battery()

Typical Info:
-------------
    present:                 yes
    design capacity:         47520 mWh
    last full capacity:      28800 mWh
    battery technology:      rechargeable
    design voltage:          10800 mV
    design capacity warning: 2376 mWh
    design capacity low:     475 mWh
    capacity granularity 1:  1 mWh
    capacity granularity 2:  1 mWh
    model number:            IBM-08K8040
    serial number:            1234
    battery type:            LION
    OEM info:                SANYO

Typical State:
---------------
    present:                 yes
    capacity state:          ok
    charging state:          charging
    present rate:            2873 mW
    remaining capacity:      27810 mWh
    present voltage:         12494 mV

*/

static char *battery_state_file="/proc/acpi/battery/BAT0/state";
static char *battery_info_file="/proc/acpi/battery/BAT0/info";

struct battery_info {
    int	    present;
    int	    design_capacity;
    int	    last_full_capacity;
    int	    state;
    int	    rate;
    int	    capacity;
    int	    voltage;
};
    

struct battery_info *	get_battery(void) {
    static struct battery_info batt;
    int fd;
    char map[4096];
    char *p;
    int n;

    fd = open(battery_info_file, O_RDONLY);
    if(fd == -1)	return (NULL);
    
    memset(map, 0, 4096);
    n = read(fd, map, 4095);
    map[n]=0x00;

    close(fd);

    p = strstr(map, "present:");
    if (!p) return (NULL);
    p += 25;
    batt.present = (strstr(p, "yes") ? 1 : 0);

    p = strstr(map, "design capacity:");
    if (!p) return (NULL);
    p += 25;
    batt.design_capacity = strtol(p, NULL, 0);

    p = strstr(map, "last full capacity:");
    if (!p) return (NULL);
    p += 25;
    batt.last_full_capacity = strtol(p, NULL, 0);

    fd = open(battery_state_file, O_RDONLY);
    if(fd == -1)
	return (NULL);

    memset(map, 0, 4096);
    n = read(fd, map, 4095);
    map[n]=0;

    close(fd);

    p = strstr(map, "charging state:");
    if (!p) return (NULL);
    p += 25;
    if (strncmp(p, "discharging", 11) == 0)
	batt.state = 0;
    else if (strncmp(p, "charging", 8) == 0)
	batt.state = 1;
    else if (strncmp(p, "charged", 7) == 0)
	batt.state = 2;
    else batt.state = 10;

    p = strstr(map, "rate:");
    if (!p) return (NULL);
    p += 25;
    batt.rate = strstr(p, "yes") ? 1 : 0;

    p = strstr(map, "remaining capacity:");
    if (!p) return (NULL);
    p += 25;
    batt.capacity = strtol(p, NULL, 0);

    p = strstr(map, "present voltage:");
    if (!p) return (NULL);
    p += 25;
    batt.voltage = strtol(p, NULL, 0);

    return (&batt);
}


/*
    Thermal data


>From linux/Documentation/ibm-acpi.txt:

    Tentative layout; varies significantly by model.

    1:  CPU
    2:  (depends on model)
    3:  (depends on model)
    4:  GPU
    5:  Main battery: main sensor
    6:  Bay battery: main sensor
    7:  Main battery: secondary sensor
    8:  Bay battery: secondary sensor
    9-15: (depends on model)


*/
static char *thermal_file="/proc/acpi/ibm/thermal";

struct thermal_info {
    int	    cpu;
    int	    mb;
    int	    gpu;
    int	    hdd;
    int	    batt0;
    int	    batt1;
    int	    batt0b;
    int	    batt1b;
};


struct thermal_info * get_temp(void) {
    static struct thermal_info temp;
    int fd, r;
    char buf[4096];
    char *p;

    fd = open(thermal_file, O_RDONLY);
    if (fd == -1)
	return(NULL);

    memset(buf, 0x00, 4096);
    r = read(fd, buf, 4096);
    if (r == -1) {
	close(fd);
	return(NULL);
    }

    buf[r] = 0x00;
    p = buf;

    while(!isdigit(*p) && *p != '+' && *p != '-')
	p++;

    /*	Here I am making an educated WAG as to the correlation
	of fields and their corresponding sensors.  This is likely
	close to being correct, but absent documentation and the will
	to freeze chips on the motherboard one-by one, I cannot be
	sure.  If you do not have a Thinkpad X30, you may have to
	make adjustments.
    */

    temp.cpu = strtol(p, &p, 0);
    while(isspace(*p))	p++;

    temp.mb = strtol(p, &p, 0);
    while(isspace(*p))	p++;

    temp.hdd = strtol(p, &p, 0);
    while(isspace(*p))	p++;

    temp.gpu = strtol(p, &p, 0);
    while(isspace(*p))	p++;

    temp.batt0 = strtol(p, &p, 0);
    while(isspace(*p))	p++;

    temp.batt1 = strtol(p, &p, 0);
    while(isspace(*p))	p++;

    temp.batt0b = strtol(p, &p, 0);
    while(isspace(*p))	p++;

    temp.batt1b = strtol(p, &p, 0);

    return(&temp);
}





int main(int argc, char **argv) {
    struct battery_info *   b;
    struct thermal_info *   t;
    char		    buf[1024];
    float		    percent;
    char		    bstate;
    int			    len=0;


    b = get_battery();
    t = get_temp();

    if(!b)
	len += sprintf(buf, "!BATT ");
    else {
	percent = (float)b->capacity / (float)b->design_capacity * 100.0;

	switch(b->state) {
	    case (0):
		bstate = '-';
		break;
	    case (1):
		bstate = '+';
		break;
	    case (2):
		bstate = ' ';
		break;
	    default:
		bstate = '!';
	}
    
	len += sprintf(buf, "Charge: %c%2.0f%%", bstate, percent);
    }

    if(!t)
	len += sprintf(buf + len, "!TEMP ");
    else {
	len += sprintf(buf + len, "   cpu:%2d mb:%2d hdd:%2d gpu:%2d batt0:%2d/%2d", t->cpu, t->mb, t->hdd, t->gpu, t->batt0, t->batt0b);
    }

    write(fileno(stdout), buf, len);

    exit(0);
}

--0-595272767-1175041460=:1263--