⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 battery.c

📁 系统任务管理器
💻 C
📖 第 1 页 / 共 3 页
字号:
/*|  Copyright (C) 1999-2006 Bill Wilson||  Author:  Bill Wilson    billw@gkrellm.net|  Latest versions might be found at:  http://gkrellm.net||  This program is free software which I release under the GNU General Public|  License. You may redistribute and/or modify this program under the terms|  of that license as published by the Free Software Foundation; either|  version 2 of the License, or (at your option) any later version.||  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.  Version 2 is in the|  COPYRIGHT file in the top level directory of this distribution.| |  To get a copy of the GNU General Puplic License, write to the Free Software|  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA*/#include "gkrellm.h"#include "gkrellm-private.h"#include "gkrellm-sysdeps.h"#include <math.h>#define	BAT_CONFIG_KEYWORD	"battery"typedef enum	{	BATTERYDISPLAY_PERCENT,	BATTERYDISPLAY_TIME,	BATTERYDISPLAY_RATE,	BATTERYDISPLAY_EOM	/* end of modes */	}	BatteryDisplayMode; typedef struct	{	gint				id;	GkrellmPanel		*panel;	GkrellmKrell		*krell;	GkrellmDecal		*power_decal;	GkrellmDecal		*time_decal;	GkrellmAlert		*alert;	gboolean			enabled;	BatteryDisplayMode	display_mode;	gfloat				charge_rate;	/* % / min */	gboolean			present,						on_line,						charging;	gint				percent;	gint				time_left;		/* In minutes, -1 if minutes unavail */	}	Battery;static GList			*battery_list;static GkrellmMonitor	*mon_battery;static GtkWidget		*battery_vbox;static Battery			*composite_battery,						*launch_battery;static gboolean			enable_composite,						enable_each,						enable_estimate;static gint				poll_interval = 5,						full_cap_fallback = 5000;static GkrellmLauncher	launch;static GkrellmAlert		*bat_alert;		/* One alert dupped for each battery */static gint				style_id;static gboolean			alert_units_percent,						alert_units_need_estimate_mode;static void		(*read_battery_data)();static void		create_battery_panel(Battery *bat, gboolean first_create);static gint		n_batteries;static Battery *battery_nth(gint n, gboolean create)	{	Battery			*bat;	if (n > 10)		return NULL;	if (n < 0)		{		if (!composite_battery && create)			{			bat = g_new0(Battery, 1);			battery_list = g_list_prepend(battery_list, bat);			bat->id = GKRELLM_BATTERY_COMPOSITE_ID;		/* -1 */			composite_battery = bat;			gkrellm_alert_dup(&bat->alert, bat_alert);			}		return composite_battery;		}	if (composite_battery)		++n;	while (   (bat = (Battery *) g_list_nth_data(battery_list, n)) == NULL		   && create		  )		{		bat = g_new0(Battery, 1);		battery_list = g_list_append(battery_list, bat);		bat->id = n_batteries++;		gkrellm_alert_dup(&bat->alert, bat_alert);		}	return bat;	}  /* Themers need to be able to see the battery monitor.  */static voidread_battery_demo(void)	{	gboolean	on_line, charging;	gint		percent, time_left;	static gint	bump = 60;	if (bump <= 5)		bump = 60;	bump -= 5;	on_line = bump > 45;	if (on_line)		{		charging = TRUE;		time_left = 200 + (60 - bump) * 20;		percent = time_left / 5;		}	else		{		charging = FALSE;		time_left = bump;		percent = 1 + bump;		}	gkrellm_battery_assign_data(0, TRUE, on_line, charging,				percent, time_left);	}static gbooleansetup_battery_interface(void)	{    if (!read_battery_data && !_GK.client_mode && gkrellm_sys_battery_init())        read_battery_data = gkrellm_sys_battery_read_data;	if (_GK.demo)		read_battery_data = read_battery_demo;    return read_battery_data ? TRUE : FALSE;	}void gkrellm_battery_client_divert(void (*read_func)())	{	read_battery_data = read_func;	}voidgkrellm_battery_assign_data(gint n, gboolean present, gboolean on_line,			gboolean charging, gint percent, gint time_left)	{	Battery	*bat;	bat = battery_nth(n, TRUE);	if (!bat)		return;	bat->present = present;	bat->on_line = on_line;	bat->charging = charging;	bat->percent = percent;	bat->time_left = time_left;	}  /* Help out some laptops with Linux ACPI bugs */gintgkrellm_battery_full_cap_fallback(void)	{	return full_cap_fallback;	}/* -------------------------------------------------------------- *//* estimate (guess-timate?) battery time remaining, based on the rate of    discharge (and conversely the time to charge based on the rate of charge).  - some BIOS' only provide battery levels, not any estimate of the time    remaining      Battery charge/discharge characteristics (or, why dc/dt doesn't really work)  - the charge/discharge curves of most battery types tend to be very non-    linear (http://www.google.com/search?q=battery+charge+discharge+curve)  - on discharge, most battery types will initially fall somewhat rapidly    from 100 percent, then flatten out and stay somewhat linear until    suddenly "dropping out" when nearly depleted (approx. 10-20% capacity).    For practical purposes we can consider this point to be the end of the    discharge curve. This is simple enough to model via a fixed capacity    offset to cut out just at the knee of this curve, and allows us to    reasonably approximate the rest of the curve by a linear function    and simple dc/dt calculation.  - with regard to charging, however, it's not quite so easy. With a    constant voltage charger, the battery capacity rises exponentially    (charging current decreases as battery terminal voltage rises). The    final stages of charging are very gradual, with a relatively long    period at "almost but not quite 100%".    Unfortunately a linear extrapolation at the beginning of an     exponential curve will be a poor approximation to the true expected    time to charge, tending to be significantly undervalued. Using an     exponential model to estimate time to approx. 90-95% (2.5 * exp. time    constant) seems to give a more reasonable fit. That said, the poor    relative resolution at higher charge values makes estimating the    exponential time constant difficult towards the end of the charge     cycle (the curve's very nearly flat). So, I've settled on a mixed     model - for c < ~70 I use an exponential model, and switch to linear    above that (or if the charge rate seems to have otherwise "flatlined").    Empirically, this method seems to give reasonable results [1] -     certainly  much better than seeing "0:50:00 to full" for a good half an    hour (i.e. as happens with apmd, which uses a linear model for both    charging + discharging). Note that a constant-current charger should    be pretty well linear all the way along the charge curve, which means    the linear rate extrapolation should work well in this case. The user    can choose which model they wish to use via estimate_model.    [1] I logged my Compaq Armada M300's capacity (via /proc/apm) over one    complete discharge/charge cycle (machine was idle the whole time). The    discharge curve was linear to approx. 14% when the BIOS alerted of     impending doom; upon plugging in the external power supply the capacity    rose exponentially to 100%, with a time constant of approx. 0.8 hr (i.e.     approx. 2+ hrs to full charge).  Linear rate of change calculation:  - in an ideal, continuous world, estimated time to 0(100) would simply     be the remaining capacity divided by the charge rate       ttl = c / dc(t)/dt  - alas, the reported battery capacity is bound to integer values thus     c(t) is a discontinuous function. i.e. has fairly large steps. And of    course then dc/dt is undefined at the discontinuities.  - to avoid this issue the rate of charge is determined by the deltas from    the start of the last state change (charge/discharge cycle) (time T)       ttl(t) = c(t) / ((C - c(t)) / (T - t))    C = charge at time T    Furthermore, the rate changes are windowed and filtered to mitigate     c(t) transients (e.g. at the start of discharge) and smooth over     discontinuities (and fudge for battery characteristics, ref. above).*/#define BAT_SLEEP_DETECT 300		/* interval of >300s => must have slept */#define BAT_DISCHARGE_TRANSIENT 10	/* ignore first 10% of discharge cycle */#define BAT_EMPTY_CAPACITY 12		/* when is the battery "flat"? */#define BAT_RATECHANGE_WINDOW 90	/* allow rate changes after 90s */#define BAT_CHARGE_MODEL_LIMIT 60	/* linear charge model cutover point */#define BAT_RATE_SMOOTHING 0.3		/* rate smoothing weight *//* #define BAT_ESTIMATE_DEBUG */  /* user-provided nominal battery runtimes, hrs (used to determine initial   |  discharge, stable, charge rate (%/min))  */static gfloat	estimate_runtime[2] = {0};static gint		estimate_model[2] = {0};static gboolean	reset_estimate;static voidestimate_battery_time_left(Battery *bat)	{	/* ?0 = at time 0 (state change); ?1 = at last "sample" (rate change) */	static time_t	t0 = -1, t1;	static gint		p0, p1;	static gint		c0;	static gfloat	rate = 0;	static time_t	dt;	static gint		dp;	time_t			t = time(NULL);	/* 1 charging; 0 power on and stable; -1 discharging */	gint			charging = bat->charging ? 1 : (bat->on_line ? 0 : -1);#ifdef BAT_ESTIMATE_DEBUG		fprintf(stderr, "%ld bc?=%d ac?=%d (%+d) bp=%d\t", t, 			bat->charging, bat->on_line, charging, 			bat->percent);#endif	if (   reset_estimate || t0 < 0 || c0 != charging		|| (t - t1) > BAT_SLEEP_DETECT	   )		{		/* init, state change, or sleep/hibernation		*/		reset_estimate = FALSE;		c0 = charging;		t0 = t1 = t;		if (charging < 0 && (bat->percent > 100 - BAT_DISCHARGE_TRANSIENT))			p0 = p1 = 100 - BAT_DISCHARGE_TRANSIENT;		else			p0 = p1 = bat->percent;		dp = dt = 0;		rate = 0.0;		/* convert runtime (hrs) to signed rate (%/min)		*/		if (charging < 0)			rate = -100 / (estimate_runtime[0] * 60);		else if (charging > 0)			rate =  100 / (estimate_runtime[1] * 60);#ifdef BAT_ESTIMATE_DEBUG		fprintf(stderr, "[r = %.3f]\t", rate);#endif		}	else		{		time_t	dt1 = t - t1;		/* delta since last rate change */		gint	dp1 = bat->percent - p1;		/* time for a rate change?		*/		if (   dt1 > BAT_RATECHANGE_WINDOW			&& ((charging > 0 && dp1 >= 0) || (charging < 0 && dp1 <= 0))		   )			{			dt = t - t0;					/* since state change */			dp = bat->percent - p0;			if (dp1 == 0)	/* flatlining (dp/dt = 0) */				rate = (1 - BAT_RATE_SMOOTHING/4) * rate;			else				rate = BAT_RATE_SMOOTHING *						((gdouble) dp / (gdouble) (dt/60)) + 						(1 - BAT_RATE_SMOOTHING) * rate;#ifdef BAT_ESTIMATE_DEBUG			fprintf(stderr, "%d [dp = %+d dt = %.2f rate = %.3f]\t",					(gint) dp1, dp, (gdouble) dt / 60, rate);#endif			t1 = t;			p1 = bat->percent;			}		}	if (charging && rate != 0.0)	/* (dis)charging */		{		gfloat	eta;		gint 	p = charging > 0 ? 100 - bat->percent : 						bat->percent - BAT_EMPTY_CAPACITY;		if (   charging > 0 && estimate_model[1]			&& bat->percent < BAT_CHARGE_MODEL_LIMIT && dp > 0		   )			/* charging, use exponential: eta =~ 2.5 * time-constant (~=92%) */			eta = -2.5 * dt/60 / (log(1 - (gdouble)dp/(gdouble)(p+dp)));		else			eta = abs((gdouble)p / rate);	/* use linear */#ifdef BAT_ESTIMATE_DEBUG		fprintf(stderr, "eta = %.2f\t", eta);#endif		/* round off to nearest 5 mins */		bat->time_left = (gint)((eta > 0 ? eta + 2.5: 0) / 5) * 5;		bat->charge_rate = rate;		}	else		{		bat->time_left = INT_MAX;	/* inf */		bat->charge_rate = 0.0;		}#ifdef BAT_ESTIMATE_DEBUG		fprintf(stderr, "\n");#endif	}static voiddraw_time_left_decal(Battery *bat, gboolean force)	{	GkrellmDecal	*d;	gchar			buf[16];	gint			x, w, t;	int				battery_display_mode = bat->display_mode;	static BatteryDisplayMode	last_mode = BATTERYDISPLAY_EOM;	if (!bat->panel)		return;	if (bat->time_left == -1)		battery_display_mode = BATTERYDISPLAY_PERCENT;	if (last_mode != battery_display_mode)		force = TRUE;	last_mode = bat->display_mode;	switch (battery_display_mode)		{		case BATTERYDISPLAY_TIME:			t = bat->time_left;			if (t == INT_MAX || t == INT_MIN)				snprintf(buf, sizeof(buf), "--");			else				snprintf(buf, sizeof(buf), "%2d:%02d", t / 60, t % 60);			break;		case BATTERYDISPLAY_RATE:			/* t is used by draw_decal_text() to see if a refresh is reqd */			t = (gint) (bat->charge_rate * 100.0);			snprintf(buf, sizeof(buf), "%0.1f%%/m",						bat->charge_rate);			break;		case BATTERYDISPLAY_PERCENT:		default:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -